Compare commits
528 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f182be3db0 | ||
|
|
81a32f6d58 | ||
|
|
82552b1748 | ||
|
|
af7a45d739 | ||
|
|
21013a6fe5 | ||
|
|
c81ad67844 | ||
|
|
13797f1fb3 | ||
|
|
ef5cd39b16 | ||
|
|
e133e944e3 | ||
|
|
2ffb5bbb63 | ||
|
|
0f16644944 | ||
|
|
0b41159ee4 | ||
|
|
2a78aea898 | ||
|
|
4c5face779 | ||
|
|
b3a8a8d30c | ||
|
|
7836750171 | ||
|
|
ef9d3d2e8f | ||
|
|
3ca846b2c2 | ||
|
|
ae7b68bc16 | ||
|
|
3150134e65 | ||
|
|
b552628b43 | ||
|
|
9b3eb4702b | ||
|
|
52fa98f918 | ||
|
|
1d874f37b2 | ||
|
|
582ba6023e | ||
|
|
fbcb522b43 | ||
|
|
1d3096d82c | ||
|
|
43ea2e7857 | ||
|
|
92038a1949 | ||
|
|
a323ddd5dd | ||
|
|
e70cdd4cc5 | ||
|
|
427a81cff6 | ||
|
|
4933c7a678 | ||
|
|
8ee2ec5749 | ||
|
|
ce4216e56c | ||
|
|
a3526d338f | ||
|
|
65041f77c3 | ||
|
|
4206993c72 | ||
|
|
a7d8dc6a66 | ||
|
|
56bdf1bc4d | ||
|
|
acb009a909 | ||
|
|
96532fa61e | ||
|
|
eed7f1917e | ||
|
|
51b99089e4 | ||
|
|
118e35e897 | ||
|
|
b9197b1eb3 | ||
|
|
568bb696a7 | ||
|
|
43616297c8 | ||
|
|
51801a03a0 | ||
|
|
59254c0294 | ||
|
|
61b238d511 | ||
|
|
d5ca5331a7 | ||
|
|
8f72d8608b | ||
|
|
425f3da9d4 | ||
|
|
34dc025b79 | ||
|
|
b2f8cda99b | ||
|
|
dd1e0c672b | ||
|
|
0e3cf56034 | ||
|
|
bfe409305c | ||
|
|
b225917a51 | ||
|
|
5359f5aca9 | ||
|
|
1d2f450ba4 | ||
|
|
4aa03ba3c5 | ||
|
|
118e34b380 | ||
|
|
ff3c5768c6 | ||
|
|
f293eefe8c | ||
|
|
49c59897bf | ||
|
|
0e53484b62 | ||
|
|
842bd4e251 | ||
|
|
003817ed9d | ||
|
|
fb68e63bd0 | ||
|
|
e6a03c3b30 | ||
|
|
fb8b3a3b09 | ||
|
|
43fd966bf1 | ||
|
|
315fa5a440 | ||
|
|
3be593f464 | ||
|
|
8c47a8b758 | ||
|
|
5515a5b4d6 | ||
|
|
cee0a92430 | ||
|
|
ddc163f286 | ||
|
|
81ce0bc708 | ||
|
|
29c870631b | ||
|
|
261674339a | ||
|
|
bfb418fdfd | ||
|
|
5c8c191151 | ||
|
|
9e558944d1 | ||
|
|
d8134f6d42 | ||
|
|
aa3ae524f4 | ||
|
|
cd2b12c35a | ||
|
|
b7e1e5764e | ||
|
|
9ef4ba4af5 | ||
|
|
86deaceade | ||
|
|
fd76d110d4 | ||
|
|
21f67651ff | ||
|
|
0cf22e96bc | ||
|
|
86eeab5e69 | ||
|
|
e8c98be687 | ||
|
|
bf04423524 | ||
|
|
25df51af78 | ||
|
|
6ef4b981fc | ||
|
|
4bd13949f6 | ||
|
|
5fea526d6c | ||
|
|
0b367efa27 | ||
|
|
8d60e8d864 | ||
|
|
047a599809 | ||
|
|
44d361b658 | ||
|
|
780976243a | ||
|
|
820dab3bfb | ||
|
|
67020213ed | ||
|
|
13e019b5e5 | ||
|
|
78c8dcb8e6 | ||
|
|
db90ae538e | ||
|
|
97484c5f1a | ||
|
|
1f6bdc30c8 | ||
|
|
19dd650510 | ||
|
|
72d57ca342 | ||
|
|
fc3258ad9a | ||
|
|
2632675cbe | ||
|
|
b7c820e87c | ||
|
|
3578ed8512 | ||
|
|
7c719b4d26 | ||
|
|
4e3de53e45 | ||
|
|
13cba9831c | ||
|
|
c02863b079 | ||
|
|
27e64380b0 | ||
|
|
2699b36ab0 | ||
|
|
420c59a862 | ||
|
|
5ece842b2c | ||
|
|
6f77cef2ab | ||
|
|
54b59ab90c | ||
|
|
01fb7f0a1a | ||
|
|
d7586c2705 | ||
|
|
b00ff1186d | ||
|
|
9bea3c487a | ||
|
|
2b2c72fe04 | ||
|
|
edadf1ea41 | ||
|
|
c8e5752395 | ||
|
|
bac2d96605 | ||
|
|
063d40f845 | ||
|
|
881ad3a110 | ||
|
|
c248f55fbd | ||
|
|
2501bf5d56 | ||
|
|
48c8613f9b | ||
|
|
b26053efa4 | ||
|
|
32ef5393e2 | ||
|
|
abc54fae4f | ||
|
|
d094001792 | ||
|
|
573e1f3865 | ||
|
|
d99f96b079 | ||
|
|
4b68708624 | ||
|
|
7e764cdf62 | ||
|
|
32dd6e6ced | ||
|
|
fb9242f637 | ||
|
|
acf4a4f4d7 | ||
|
|
260a53aaf1 | ||
|
|
42d4829f2e | ||
|
|
6ac6f0a441 | ||
|
|
54ad666355 | ||
|
|
43f4cc6c9e | ||
|
|
6219ceb0a2 | ||
|
|
725c99211b | ||
|
|
bcf29eea45 | ||
|
|
0d4546bb9e | ||
|
|
e4ce12057b | ||
|
|
19ecd12c5f | ||
|
|
b96e55f42c | ||
|
|
31d4018698 | ||
|
|
ef26003755 | ||
|
|
931d311281 | ||
|
|
01eda98415 | ||
|
|
1b0fe9d352 | ||
|
|
f31db95241 | ||
|
|
ebedde5ed6 | ||
|
|
8e2ab6c2c4 | ||
|
|
e1308b6fd5 | ||
|
|
a5b3caea11 | ||
|
|
de1495ee2e | ||
|
|
7a78dd6547 | ||
|
|
8cdb869a10 | ||
|
|
f5639ec79d | ||
|
|
3d31728194 | ||
|
|
a996eaf53c | ||
|
|
f0b6cf9712 | ||
|
|
470685a94f | ||
|
|
c10b2c49b5 | ||
|
|
f1aa0e4817 | ||
|
|
82e31fffd8 | ||
|
|
cdc5d2ee6c | ||
|
|
3d26a73b05 | ||
|
|
b1fb38027d | ||
|
|
eef1139c0d | ||
|
|
cb0bdb89c5 | ||
|
|
d6a4b11b65 | ||
|
|
a80a75ca77 | ||
|
|
a56c66d19f | ||
|
|
bc7e2483c2 | ||
|
|
00decf1f6c | ||
|
|
306b524dee | ||
|
|
f26772d4a0 | ||
|
|
e39ab31397 | ||
|
|
208a1568b3 | ||
|
|
a7a4c18715 | ||
|
|
9228976803 | ||
|
|
6619b9f4de | ||
|
|
9f1f654521 | ||
|
|
ad974ef07b | ||
|
|
ff8009167b | ||
|
|
b3dc8b04c8 | ||
|
|
5684f97389 | ||
|
|
bce93733c9 | ||
|
|
c677bc17e4 | ||
|
|
91e344ae28 | ||
|
|
f4ad886a79 | ||
|
|
ef51c2dbe3 | ||
|
|
8984078767 | ||
|
|
59231003ea | ||
|
|
fb2fa6e6c2 | ||
|
|
dc253b0254 | ||
|
|
f3c1de430b | ||
|
|
af5adade4d | ||
|
|
d150fe6f80 | ||
|
|
ff132b2d87 | ||
|
|
90e8af9765 | ||
|
|
ab27b6f63b | ||
|
|
dcc711d4eb | ||
|
|
95d57642c4 | ||
|
|
7252119228 | ||
|
|
0adf3288c8 | ||
|
|
b30a6e159c | ||
|
|
3c8a814abb | ||
|
|
42093b81b2 | ||
|
|
f11ffa18a1 | ||
|
|
8f541081ae | ||
|
|
6a215c0440 | ||
|
|
ada527370f | ||
|
|
97f0230ac5 | ||
|
|
1070d62e47 | ||
|
|
ba3cb01f02 | ||
|
|
c52116f4e7 | ||
|
|
c787881c76 | ||
|
|
fa7fd420a8 | ||
|
|
12d30af308 | ||
|
|
4695d31c72 | ||
|
|
866e6ac45a | ||
|
|
b1f8453daf | ||
|
|
317d6d576b | ||
|
|
d66ea4e154 | ||
|
|
bcfb915d93 | ||
|
|
e5c3d9c07b | ||
|
|
8a8c1b957f | ||
|
|
76b7ec9bc5 | ||
|
|
78fa17dc73 | ||
|
|
e678f6f4b3 | ||
|
|
2eb6d7b27c | ||
|
|
5805bb2a33 | ||
|
|
e92c7632d5 | ||
|
|
370b116656 | ||
|
|
35ebe4774f | ||
|
|
8fab3fc04d | ||
|
|
3dc63bf77c | ||
|
|
305bde5561 | ||
|
|
048356bf3f | ||
|
|
b389b07a6e | ||
|
|
7f72ef0021 | ||
|
|
395c9b0cd3 | ||
|
|
7e44bdf1e2 | ||
|
|
9e0ec97845 | ||
|
|
0259bcee06 | ||
|
|
64e7cce171 | ||
|
|
4e39914cff | ||
|
|
5347f986e4 | ||
|
|
7dd24698b1 | ||
|
|
a8534a8b13 | ||
|
|
d15cedd6d1 | ||
|
|
51e46f20f4 | ||
|
|
3a5a91f1e1 | ||
|
|
7e910b9339 | ||
|
|
0fbf580293 | ||
|
|
d8b20774f4 | ||
|
|
63af59e624 | ||
|
|
61e9df1844 | ||
|
|
a2823df27e | ||
|
|
7557025b01 | ||
|
|
96662844b2 | ||
|
|
16e7cdaa1f | ||
|
|
feffcd5cdc | ||
|
|
89d26778f2 | ||
|
|
b7ea2ac415 | ||
|
|
bb1f86c9d2 | ||
|
|
cc972db41d | ||
|
|
d9ce51f7e3 | ||
|
|
5dd75f836c | ||
|
|
b45627b4a7 | ||
|
|
404e783060 | ||
|
|
3515b9a942 | ||
|
|
b244d1e4b4 | ||
|
|
c4729167cd | ||
|
|
a7b652c137 | ||
|
|
d396b782a7 | ||
|
|
965166a349 | ||
|
|
733f811f9d | ||
|
|
7e42932028 | ||
|
|
cdc58066f6 | ||
|
|
224dafcae6 | ||
|
|
bb3f59f1bb | ||
|
|
876127d1fb | ||
|
|
f27807097d | ||
|
|
68bfcf6700 | ||
|
|
829e009d4c | ||
|
|
6dbe365362 | ||
|
|
db1d65e601 | ||
|
|
767e688d3c | ||
|
|
e647d4b355 | ||
|
|
b85559c686 | ||
|
|
6f353ce01d | ||
|
|
5dfea0175d | ||
|
|
b4c0ce17de | ||
|
|
c805887bbd | ||
|
|
d4b419ded8 | ||
|
|
a5e70e9def | ||
|
|
d06cd4be54 | ||
|
|
20d0334489 | ||
|
|
5438e800c7 | ||
|
|
4593b09bf3 | ||
|
|
33ed133f9f | ||
|
|
fe2214d12c | ||
|
|
2e41ac041e | ||
|
|
98c3f749d8 | ||
|
|
851b9fb3b2 | ||
|
|
6aea290693 | ||
|
|
ace0ecfce1 | ||
|
|
a8c4f6dd29 | ||
|
|
3818741453 | ||
|
|
da3c18fde2 | ||
|
|
9836c2aab5 | ||
|
|
46202a0b64 | ||
|
|
16a8d91815 | ||
|
|
6f5cd79a7f | ||
|
|
bf7fab3600 | ||
|
|
d4653ca983 | ||
|
|
c9444d7747 | ||
|
|
287b95a538 | ||
|
|
686f390b1a | ||
|
|
46fba3ca5a | ||
|
|
7d2f07d6b0 | ||
|
|
6f9d2a7c85 | ||
|
|
59998396d4 | ||
|
|
60e151db0f | ||
|
|
211d81ab7a | ||
|
|
eb255daac2 | ||
|
|
032b1eeabe | ||
|
|
4526138fae | ||
|
|
428f1dd5fb | ||
|
|
4f4f286a5e | ||
|
|
05799650e6 | ||
|
|
d67bef3001 | ||
|
|
76d329b888 | ||
|
|
0329e74bbd | ||
|
|
9fabb7223a | ||
|
|
671c44438d | ||
|
|
2377fbff55 | ||
|
|
af17c026ff | ||
|
|
7a1e968a52 | ||
|
|
8e9f6e19bf | ||
|
|
bef117a22c | ||
|
|
d4a50efc38 | ||
|
|
6693933941 | ||
|
|
b627b181e3 | ||
|
|
fcf159d091 | ||
|
|
aa9de3c369 | ||
|
|
b989da3f05 | ||
|
|
cdf39fd838 | ||
|
|
c3fbb9100a | ||
|
|
fbc7dfce60 | ||
|
|
bde8bd8475 | ||
|
|
c713b9d2f4 | ||
|
|
25a0848c3e | ||
|
|
ccd008666e | ||
|
|
40d9eb15cf | ||
|
|
fad870e83e | ||
|
|
0f494b10d0 | ||
|
|
b2091d4f83 | ||
|
|
7b9c0d85cd | ||
|
|
5662cccc98 | ||
|
|
2b6001402a | ||
|
|
8d9df1f397 | ||
|
|
aa30982ff1 | ||
|
|
c5f072f6b6 | ||
|
|
fb8e66e32d | ||
|
|
d457f9a46f | ||
|
|
6bbe992940 | ||
|
|
1cb658f9d1 | ||
|
|
b3de35eac7 | ||
|
|
5bb7c780a1 | ||
|
|
5c5d1dc877 | ||
|
|
8ab324f69e | ||
|
|
e30a54297a | ||
|
|
c4fc832ef6 | ||
|
|
750312c59e | ||
|
|
e8665f7484 | ||
|
|
81669177cd | ||
|
|
dc063218ff | ||
|
|
004025636c | ||
|
|
5a2e806e4a | ||
|
|
b918933665 | ||
|
|
e39e2522aa | ||
|
|
8caa92d663 | ||
|
|
0be67a8589 | ||
|
|
d0250f3fd0 | ||
|
|
a11bb2282f | ||
|
|
664410821c | ||
|
|
a2a0defa23 | ||
|
|
c6595c6481 | ||
|
|
cbedb8370b | ||
|
|
b92d9c9e04 | ||
|
|
bd054ecedd | ||
|
|
9dfa101afe | ||
|
|
f52a378280 | ||
|
|
bda96f952e | ||
|
|
79fb9bd785 | ||
|
|
5de6b359ee | ||
|
|
b5f1afb81e | ||
|
|
63e53cb2ed | ||
|
|
7f08355311 | ||
|
|
76403ef8ea | ||
|
|
12768b5219 | ||
|
|
aa2012bbda | ||
|
|
179abe4f37 | ||
|
|
43154346e3 | ||
|
|
1b9128a68f | ||
|
|
b5b465d56f | ||
|
|
94cbb2cf3d | ||
|
|
a51e68c3d8 | ||
|
|
7208126584 | ||
|
|
256305d12f | ||
|
|
7996bc7e23 | ||
|
|
e86a7cf59f | ||
|
|
6abcbc96ac | ||
|
|
b23c3e60d7 | ||
|
|
2f6d460442 | ||
|
|
3cd1eaeddc | ||
|
|
feb3aa34e9 | ||
|
|
7f8c622f6b | ||
|
|
6628cf3495 | ||
|
|
e6f3cd77de | ||
|
|
8705524a4b | ||
|
|
4475f5979e | ||
|
|
93321437c1 | ||
|
|
0bf7f5f9ce | ||
|
|
ef8b1bc58e | ||
|
|
8f938c825d | ||
|
|
766ba97a0e | ||
|
|
24c433dd5b | ||
|
|
570dc20e8e | ||
|
|
34be5155c4 | ||
|
|
e752e4607c | ||
|
|
9e5ab63434 | ||
|
|
66cd961fc3 | ||
|
|
6216dd8bac | ||
|
|
3677b7d761 | ||
|
|
eae53022ee | ||
|
|
24e793582d | ||
|
|
01b8948b6a | ||
|
|
1b3dbfc98d | ||
|
|
a2930ccfdd | ||
|
|
201f4ca07f | ||
|
|
e81e8e7252 | ||
|
|
9d01fb5784 | ||
|
|
9921e868bc | ||
|
|
9dd6085bcf | ||
|
|
2d1928ebd0 | ||
|
|
095853d090 | ||
|
|
fe46e69c53 | ||
|
|
a55571a381 | ||
|
|
7d449d3ff7 | ||
|
|
db1257751a | ||
|
|
43830f463d | ||
|
|
e798197110 | ||
|
|
35f2161913 | ||
|
|
6f8edaf4ba | ||
|
|
80a713d850 | ||
|
|
ed518d6910 | ||
|
|
7ad36ea6f6 | ||
|
|
65fc2971ac | ||
|
|
4438f90af4 | ||
|
|
2daa033b8e | ||
|
|
726f909589 | ||
|
|
6a6db17d2c | ||
|
|
021775d3a7 | ||
|
|
88ef8830c2 | ||
|
|
eb9bd777e0 | ||
|
|
e3ef820bac | ||
|
|
9317f55d81 | ||
|
|
5d7849be45 | ||
|
|
74b4c1a11f | ||
|
|
0f79f04f52 | ||
|
|
ea07686946 | ||
|
|
3df6005549 | ||
|
|
511f24e3ef | ||
|
|
4e49d2d7a6 | ||
|
|
c7e03043e0 | ||
|
|
f85626a8e4 | ||
|
|
6282675682 | ||
|
|
747d8157b5 | ||
|
|
1bcd1869f0 | ||
|
|
95c273e7b2 | ||
|
|
6236275528 | ||
|
|
d654bcfc4b | ||
|
|
fcbffdad8f | ||
|
|
8079079217 | ||
|
|
87fa2df399 | ||
|
|
5d6d69c8c4 | ||
|
|
538f36aebc | ||
|
|
9067272382 | ||
|
|
bc430a796f | ||
|
|
24fc875cc9 | ||
|
|
c4c549fe1b | ||
|
|
e41ac70dfe | ||
|
|
59ce4177d2 | ||
|
|
0af6e45868 | ||
|
|
1bbef9eb37 | ||
|
|
35342707f0 | ||
|
|
c1fc52223b | ||
|
|
30c1f8628b | ||
|
|
66df5f807c | ||
|
|
f25d134590 | ||
|
|
10fa81e77c | ||
|
|
613a7429b8 |
@ -16,6 +16,7 @@
|
||||
},
|
||||
"rules": {
|
||||
"rxjs/no-ignored-subscription": "warn",
|
||||
"@angular-eslint/prefer-standalone": "off",
|
||||
"@angular-eslint/no-conflicting-lifecycle": "error",
|
||||
"@angular-eslint/no-host-metadata-property": "error",
|
||||
"@angular-eslint/no-input-rename": "error",
|
||||
|
||||
@ -4,38 +4,60 @@ variables:
|
||||
PROJECT: red-ui
|
||||
DOCKERFILELOCATION: 'docker/$PROJECT/Dockerfile'
|
||||
|
||||
|
||||
include:
|
||||
- project: 'gitlab/gitlab'
|
||||
ref: 'main'
|
||||
file: 'ci-templates/docker_build_nexus_v2.yml'
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE != "schedule"
|
||||
- if: $CI_PIPELINE_SOURCE != "schedule"
|
||||
|
||||
sonarqube:
|
||||
stage: test
|
||||
image:
|
||||
name: sonarsource/sonar-scanner-cli:11.1
|
||||
entrypoint:
|
||||
- ''
|
||||
variables:
|
||||
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
|
||||
GIT_DEPTH: '0'
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}"
|
||||
paths:
|
||||
- ".sonar/cache"
|
||||
script:
|
||||
- sonar-scanner
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
- if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"
|
||||
- if: "$CI_COMMIT_BRANCH =~ /^release/"
|
||||
|
||||
localazy update:
|
||||
image: node:20.5
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- yarn.lock
|
||||
paths:
|
||||
- .yarn-cache/
|
||||
script:
|
||||
- git config user.email "${CI_EMAIL}"
|
||||
- git config user.name "${CI_USERNAME}"
|
||||
- git remote add gitlab_origin https://${CI_USERNAME}:${CI_ACCESS_TOKEN}@gitlab.knecon.com/redactmanager/red-ui.git
|
||||
- cd tools/localazy
|
||||
- yarn install --cache-folder .yarn-cache
|
||||
- yarn start
|
||||
- cd ../..
|
||||
- git add .
|
||||
- |-
|
||||
CHANGES=$(git status --porcelain | wc -l)
|
||||
if [ "$CHANGES" -gt "0" ]
|
||||
then
|
||||
git status
|
||||
git commit -m "push back localazy update"
|
||||
git push gitlab_origin HEAD:${CI_COMMIT_REF_NAME}
|
||||
fi
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
image: node:20.5
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- yarn.lock
|
||||
paths:
|
||||
- .yarn-cache/
|
||||
script:
|
||||
# - git config user.email "${CI_EMAIL}"
|
||||
# - git config user.name "${CI_USERNAME}"
|
||||
# - git remote add gitlab_origin https://${CI_USERNAME}:${CI_ACCESS_TOKEN}@gitlab.knecon.com/redactmanager/red-ui.git
|
||||
- git push https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.knecon.com/redactmanager/red-ui.git
|
||||
- cd tools/localazy
|
||||
- yarn install --cache-folder .yarn-cache
|
||||
- yarn start
|
||||
- cd ../..
|
||||
- git add .
|
||||
- |-
|
||||
CHANGES=$(git status --porcelain | wc -l)
|
||||
if [ "$CHANGES" -gt "0" ]
|
||||
then
|
||||
git status
|
||||
git commit -m "push back localazy update"
|
||||
git push gitlab_origin HEAD:${CI_COMMIT_REF_NAME}
|
||||
# git push https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.knecon.com/redactmanager/red-ui.git
|
||||
# git push
|
||||
fi
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/@pdftron/webviewer/public/",
|
||||
"output": "/assets/wv-resources/10.10.1/"
|
||||
"output": "/assets/wv-resources/11.1.0/"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
@ -73,7 +73,7 @@
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["./apps/red-ui/src/assets/styles", "./libs/common-ui/src/assets/styles"]
|
||||
},
|
||||
"scripts": ["node_modules/@pdftron/webviewer/webviewer.min.js", "node_modules/chart.js/auto/auto.cjs"],
|
||||
"scripts": ["node_modules/chart.js/auto/auto.cjs"],
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"optimization": false,
|
||||
|
||||
@ -4,26 +4,27 @@ import { UserPreferenceService } from '@users/user-preference.service';
|
||||
import { getConfig } from '@iqser/common-ui';
|
||||
import { AppConfig } from '@red/domain';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { filter, map, switchMap, take } from 'rxjs/operators';
|
||||
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
|
||||
import { APP_TYPE_PATHS } from '@common-ui/utils/constants';
|
||||
import { MatIconRegistry } from '@angular/material/icon';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { TenantsService } from '@common-ui/tenants';
|
||||
|
||||
function loadCustomTheme() {
|
||||
const cssFileName = getConfig<AppConfig>().THEME;
|
||||
|
||||
if (cssFileName) {
|
||||
const head = document.getElementsByTagName('head')[0];
|
||||
const link = document.createElement('link');
|
||||
link.id = cssFileName;
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = 'assets/styles/themes/' + cssFileName + '.css';
|
||||
link.media = 'all';
|
||||
head.appendChild(link);
|
||||
}
|
||||
export function loadCustomTheme(cssFileName: string) {
|
||||
const head = document.getElementsByTagName('head')[0];
|
||||
const link = document.createElement('link');
|
||||
link.id = cssFileName;
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = 'assets/styles/themes/' + cssFileName + '.css';
|
||||
link.media = 'all';
|
||||
head.appendChild(link);
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-root',
|
||||
templateUrl: './app.component.html',
|
||||
standalone: false,
|
||||
})
|
||||
export class AppComponent {
|
||||
constructor(
|
||||
@ -34,9 +35,12 @@ export class AppComponent {
|
||||
userPreferenceService: UserPreferenceService,
|
||||
renderer: Renderer2,
|
||||
private readonly _router: Router,
|
||||
private readonly _iconRegistry: MatIconRegistry,
|
||||
private readonly _sanitizer: DomSanitizer,
|
||||
private readonly _tenantsService: TenantsService,
|
||||
) {
|
||||
const config = getConfig<AppConfig>();
|
||||
renderer.addClass(document.body, userPreferenceService.getTheme());
|
||||
loadCustomTheme();
|
||||
|
||||
const removeQueryParams = _router.events.pipe(
|
||||
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
|
||||
@ -47,9 +51,25 @@ export class AppComponent {
|
||||
);
|
||||
removeQueryParams.subscribe();
|
||||
|
||||
if (getConfig().IS_DOCUMINE) {
|
||||
document.getElementById('favicon').setAttribute('href', 'assets/icons/documine-logo.ico');
|
||||
}
|
||||
this._tenantsService
|
||||
.waitForSettingTenant()
|
||||
.pipe(
|
||||
tap(() => {
|
||||
const isDocumine = this._tenantsService.activeTenant.documine;
|
||||
const logo = isDocumine ? 'documine' : 'redaction';
|
||||
_iconRegistry.addSvgIconInNamespace(
|
||||
'iqser',
|
||||
'logo',
|
||||
_sanitizer.bypassSecurityTrustResourceUrl(`/assets/icons/general/${logo}-logo.svg`),
|
||||
);
|
||||
if (isDocumine) {
|
||||
document.getElementById('favicon').setAttribute('href', 'assets/icons/documine-logo.ico');
|
||||
}
|
||||
loadCustomTheme(isDocumine ? APP_TYPE_PATHS.SCM : APP_TYPE_PATHS.REDACT);
|
||||
}),
|
||||
take(1),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
#removeKeycloakQueryParams() {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { APP_BASE_HREF, DatePipe as BaseDatePipe } from '@angular/common';
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { ENVIRONMENT_INITIALIZER, ErrorHandler, inject, NgModule } from '@angular/core';
|
||||
import { ErrorHandler, inject, NgModule, provideEnvironmentInitializer } from '@angular/core';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { MatMenu, MatMenuContent, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
||||
@ -117,7 +117,7 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
resetTimeoutOnDuplicate: true,
|
||||
}),
|
||||
TenantsModule.forRoot(),
|
||||
IqserTranslateModule.forRoot({ pathPrefix: config.BASE_TRANSLATIONS_DIRECTORY || '/assets/i18n/redact/' }),
|
||||
IqserTranslateModule.forRoot({ pathPrefix: config.BASE_TRANSLATIONS_DIRECTORY }),
|
||||
IqserLoadingModule.forRoot(),
|
||||
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
|
||||
LoggerModule.forRoot(undefined, {
|
||||
@ -135,20 +135,20 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
features: {
|
||||
ANNOTATIONS: {
|
||||
color: 'aqua',
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
level: NgxLoggerLevel.DEBUG,
|
||||
},
|
||||
FILTERS: {
|
||||
enabled: false,
|
||||
},
|
||||
TENANTS: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
},
|
||||
ROUTES: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
},
|
||||
PDF: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
},
|
||||
FILE: {
|
||||
enabled: false,
|
||||
@ -171,6 +171,9 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
DOSSIERS_CHANGES: {
|
||||
enabled: false,
|
||||
},
|
||||
GUARDS: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
} as ILoggerConfig,
|
||||
},
|
||||
@ -230,14 +233,10 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
provide: ErrorHandler,
|
||||
useClass: GlobalErrorHandler,
|
||||
},
|
||||
{
|
||||
provide: ENVIRONMENT_INITIALIZER,
|
||||
multi: true,
|
||||
useValue: async () => {
|
||||
const languageService = inject(LanguageService);
|
||||
return languageService.setInitialLanguage();
|
||||
},
|
||||
},
|
||||
provideEnvironmentInitializer(async () => {
|
||||
const languageService = inject(LanguageService);
|
||||
return languageService.setInitialLanguage();
|
||||
}),
|
||||
{
|
||||
provide: MAX_RETRIES_ON_SERVER_ERROR,
|
||||
useFactory: () => config.MAX_RETRIES_ON_SERVER_ERROR,
|
||||
@ -258,6 +257,7 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
provide: MAT_TOOLTIP_DEFAULT_OPTIONS,
|
||||
useValue: {
|
||||
disableTooltipInteractivity: true,
|
||||
showDelay: 1,
|
||||
},
|
||||
},
|
||||
BaseDatePipe,
|
||||
|
||||
@ -7,6 +7,7 @@ import { AppConfig } from '@red/domain';
|
||||
selector: 'redaction-auth-error',
|
||||
templateUrl: './auth-error.component.html',
|
||||
styleUrls: ['./auth-error.component.scss'],
|
||||
standalone: false,
|
||||
})
|
||||
export class AuthErrorComponent {
|
||||
readonly #config = getConfig<AppConfig>();
|
||||
|
||||
@ -20,6 +20,7 @@ const isSearchScreen: (url: string) => boolean = url => url.includes('/search');
|
||||
@Component({
|
||||
templateUrl: './base-screen.component.html',
|
||||
styleUrls: ['./base-screen.component.scss'],
|
||||
standalone: false,
|
||||
})
|
||||
export class BaseScreenComponent {
|
||||
readonly roles = Roles;
|
||||
|
||||
@ -7,6 +7,7 @@ import { Breadcrumb, BreadcrumbDisplayType, BreadcrumbsService } from '@services
|
||||
selector: 'redaction-breadcrumbs',
|
||||
templateUrl: './breadcrumbs.component.html',
|
||||
styleUrls: ['./breadcrumbs.component.scss'],
|
||||
standalone: false,
|
||||
})
|
||||
export class BreadcrumbsComponent {
|
||||
constructor(readonly breadcrumbsService: BreadcrumbsService) {}
|
||||
|
||||
@ -13,6 +13,7 @@ import { firstValueFrom } from 'rxjs';
|
||||
entitiesService: FileDownloadService,
|
||||
component: DownloadsListScreenComponent,
|
||||
}),
|
||||
standalone: false,
|
||||
})
|
||||
export class DownloadsListScreenComponent extends ListingComponent<DownloadStatus> implements OnDestroy {
|
||||
readonly #interval: number;
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
.mat-mdc-menu-item.notification {
|
||||
padding: 8px 26px 10px 8px;
|
||||
padding: 8px 26px 10px 8px !important;
|
||||
margin: 2px 0 0 0;
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
|
||||
@ -25,6 +25,7 @@ function chronologically(first: string, second: string) {
|
||||
selector: 'redaction-notifications',
|
||||
templateUrl: './notifications.component.html',
|
||||
styleUrls: ['./notifications.component.scss'],
|
||||
standalone: false,
|
||||
})
|
||||
export class NotificationsComponent {
|
||||
readonly hasUnreadNotifications$: Observable<boolean>;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
.container {
|
||||
padding: 32px;
|
||||
width: 900px;
|
||||
width: 1000px;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@ -5,5 +5,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
templateUrl: './dashboard-skeleton.component.html',
|
||||
styleUrls: ['./dashboard-skeleton.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class DashboardSkeletonComponent {}
|
||||
|
||||
@ -5,6 +5,7 @@ import { ChangeDetectionStrategy, Component, OnInit, TemplateRef, ViewChild } fr
|
||||
templateUrl: './dossier-skeleton.component.html',
|
||||
styleUrls: ['./dossier-skeleton.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class DossierSkeletonComponent implements OnInit {
|
||||
@ViewChild('workload1', { static: true }) workload1: TemplateRef<unknown>;
|
||||
|
||||
@ -5,5 +5,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
templateUrl: './skeleton-stats.component.html',
|
||||
styleUrls: ['./skeleton-stats.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class SkeletonStatsComponent {}
|
||||
|
||||
@ -6,6 +6,7 @@ import { Title } from '@angular/platform-browser';
|
||||
templateUrl: './skeleton-top-bar.component.html',
|
||||
styleUrls: ['./skeleton-top-bar.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class SkeletonTopBarComponent {
|
||||
constructor(readonly titleService: Title) {}
|
||||
|
||||
@ -9,6 +9,7 @@ import { MatMenuTrigger } from '@angular/material/menu';
|
||||
templateUrl: './spotlight-search.component.html',
|
||||
styleUrls: ['./spotlight-search.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: false,
|
||||
})
|
||||
export class SpotlightSearchComponent {
|
||||
@Input() actions: readonly SpotlightSearchAction[];
|
||||
|
||||
@ -9,6 +9,7 @@ interface ITenant extends IStoredTenantId {
|
||||
selector: 'app-tenants-menu',
|
||||
templateUrl: './tenants-menu.component.html',
|
||||
styleUrls: ['./tenants-menu.component.scss'],
|
||||
standalone: false,
|
||||
})
|
||||
export class TenantsMenuComponent {
|
||||
readonly tenantsService = inject(TenantsService);
|
||||
|
||||
@ -20,6 +20,7 @@ interface MenuItem {
|
||||
selector: 'app-user-menu',
|
||||
templateUrl: './user-menu.component.html',
|
||||
styleUrls: ['./user-menu.component.scss'],
|
||||
standalone: false,
|
||||
})
|
||||
export class UserMenuComponent {
|
||||
readonly currentUser = getCurrentUser<User>();
|
||||
|
||||
@ -11,7 +11,9 @@ import { DictionaryService } from '@services/entity-services/dictionary.service'
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
import { WatermarkService } from '@services/entity-services/watermark.service';
|
||||
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
|
||||
import { getConfig } from '@iqser/common-ui';
|
||||
import { getConfig, Toaster } from '@iqser/common-ui';
|
||||
import { RulesService } from '../modules/admin/services/rules.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
export function templateExistsWhenEnteringAdmin(): CanActivateFn {
|
||||
return async function (route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||
@ -21,12 +23,14 @@ export function templateExistsWhenEnteringAdmin(): CanActivateFn {
|
||||
const defaultColorsService = inject(DefaultColorsService);
|
||||
const watermarksService = inject(WatermarkService);
|
||||
const router = inject(Router);
|
||||
const rulesService = inject(RulesService);
|
||||
const isDocumine = getConfig().IS_DOCUMINE;
|
||||
|
||||
const dossierTemplate = inject(DossierTemplateStatsService).get(dossierTemplateId);
|
||||
await firstValueFrom(fileAttributesService.loadFileAttributesConfig(dossierTemplateId));
|
||||
await firstValueFrom(dictionaryService.loadDictionaryDataForDossierTemplate(dossierTemplateId));
|
||||
await firstValueFrom(defaultColorsService.loadForDossierTemplate(dossierTemplateId));
|
||||
await firstValueFrom(rulesService.getFor(dossierTemplateId));
|
||||
if (!isDocumine) {
|
||||
await firstValueFrom(watermarksService.loadForDossierTemplate(dossierTemplateId));
|
||||
}
|
||||
@ -50,6 +54,8 @@ export function templateExistsWhenEnteringDossierList(): CanActivateFn {
|
||||
const dictionaryService = inject(DictionaryService);
|
||||
const defaultColorsService = inject(DefaultColorsService);
|
||||
const watermarksService = inject(WatermarkService);
|
||||
const rulesService = inject(RulesService);
|
||||
const toaster = inject(Toaster);
|
||||
const isDocumine = getConfig().IS_DOCUMINE;
|
||||
|
||||
await firstValueFrom(dashboardStatsService.loadForTemplate(dossierTemplateId));
|
||||
@ -64,6 +70,10 @@ export function templateExistsWhenEnteringDossierList(): CanActivateFn {
|
||||
await firstValueFrom(fileAttributesService.loadFileAttributesConfig(dossierTemplateId));
|
||||
await firstValueFrom(dictionaryService.loadDictionaryDataForDossierTemplate(dossierTemplateId));
|
||||
await firstValueFrom(defaultColorsService.loadForDossierTemplate(dossierTemplateId));
|
||||
const rules = await firstValueFrom(rulesService.getFor(dossierTemplateId));
|
||||
if (rules.timeoutDetected) {
|
||||
toaster.error(_('dossier-listing.rules.timeoutError'));
|
||||
}
|
||||
if (!isDocumine) {
|
||||
await firstValueFrom(watermarksService.loadForDossierTemplate(dossierTemplateId));
|
||||
}
|
||||
|
||||
@ -40,8 +40,7 @@ export function ifLoggedIn(): AsyncGuard {
|
||||
|
||||
logger.info('[KEYCLOAK] Keycloak init...');
|
||||
await keycloakInitializer(tenant);
|
||||
logger.info('[KEYCLOAK] Keycloak init done!');
|
||||
console.log({ tenant });
|
||||
logger.info('[KEYCLOAK] Keycloak init done for tenant: ', { tenant });
|
||||
await tenantsService.selectTenant(tenant);
|
||||
await usersService.initialize();
|
||||
await licenseService.loadLicenses();
|
||||
@ -51,6 +50,7 @@ export function ifLoggedIn(): AsyncGuard {
|
||||
const jwtToken = jwtDecode(token) as JwtToken;
|
||||
const authTime = (jwtToken.auth_time || jwtToken.iat).toString();
|
||||
localStorage.setItem('authTime', authTime);
|
||||
localStorage.setItem('token', token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { AnnotationPermissions } from '@models/file/annotation.permissions';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { Dictionary, LogEntryEngines, SuperTypes } from '@red/domain';
|
||||
import { Dictionary, SuperTypes } from '@red/domain';
|
||||
|
||||
export const canUndo = (annotation: AnnotationWrapper, isApprover: boolean) => !isApprover && annotation.pending;
|
||||
|
||||
@ -24,7 +24,7 @@ export const canRemoveOnlyHere = (annotation: AnnotationWrapper, canAddRedaction
|
||||
(annotation.isRedacted || (annotation.isHint && !annotation.isImage));
|
||||
|
||||
export const canRemoveFromDictionary = (annotation: AnnotationWrapper, autoAnalysisDisabled: boolean) =>
|
||||
annotation.isModifyDictionary &&
|
||||
(annotation.isModifyDictionary || annotation.engines.includes('DICTIONARY') || annotation.engines.includes('DOSSIER_DICTIONARY')) &&
|
||||
(annotation.isRedacted || annotation.isSkipped || annotation.isHint || (annotation.isIgnoredHint && !annotation.isRuleBased)) &&
|
||||
(autoAnalysisDisabled || !annotation.pending) &&
|
||||
annotation.isDictBased;
|
||||
@ -69,3 +69,5 @@ export const canEditHint = (annotation: AnnotationWrapper) =>
|
||||
((annotation.isHint && !annotation.isRuleBased) || annotation.isIgnoredHint) && !annotation.isImage;
|
||||
|
||||
export const canEditImage = (annotation: AnnotationWrapper) => annotation.isImage;
|
||||
|
||||
export const canRevertChanges = (annotation: AnnotationWrapper) => annotation.hasRedactionChanges;
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
canRemoveRedaction,
|
||||
canResizeAnnotation,
|
||||
canResizeInDictionary,
|
||||
canRevertChanges,
|
||||
canUndo,
|
||||
} from './annotation-permissions.utils';
|
||||
import { AnnotationWrapper } from './annotation.wrapper';
|
||||
@ -37,6 +38,7 @@ export class AnnotationPermissions {
|
||||
canEditAnnotations = true;
|
||||
canEditHints = true;
|
||||
canEditImages = true;
|
||||
canRevertChanges = true;
|
||||
|
||||
static forUser(
|
||||
isApprover: boolean,
|
||||
@ -75,6 +77,7 @@ export class AnnotationPermissions {
|
||||
permissions.canEditAnnotations = canEditAnnotation(annotation);
|
||||
permissions.canEditHints = canEditHint(annotation);
|
||||
permissions.canEditImages = canEditImage(annotation);
|
||||
permissions.canRevertChanges = canRevertChanges(annotation);
|
||||
summedPermissions._merge(permissions);
|
||||
}
|
||||
return summedPermissions;
|
||||
@ -97,6 +100,7 @@ export class AnnotationPermissions {
|
||||
result.canEditAnnotations = permissions.reduce((acc, next) => acc && next.canEditAnnotations, true);
|
||||
result.canEditHints = permissions.reduce((acc, next) => acc && next.canEditHints, true);
|
||||
result.canEditImages = permissions.reduce((acc, next) => acc && next.canEditImages, true);
|
||||
result.canRevertChanges = permissions.reduce((acc, next) => acc && next.canRevertChanges, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,12 @@ import {
|
||||
} from '@red/domain';
|
||||
import { annotationTypesTranslations } from '@translations/annotation-types-translations';
|
||||
|
||||
interface AnnotationContent {
|
||||
translation: string;
|
||||
params: { [key: string]: string };
|
||||
untranslatedContent: string;
|
||||
}
|
||||
|
||||
export class AnnotationWrapper implements IListable {
|
||||
id: string;
|
||||
superType: SuperType;
|
||||
@ -34,9 +40,9 @@ export class AnnotationWrapper implements IListable {
|
||||
typeLabel?: string;
|
||||
color: string;
|
||||
numberOfComments = 0;
|
||||
firstTopLeftPoint: IPoint;
|
||||
firstBottomLeftPoint: IPoint;
|
||||
shortContent: string;
|
||||
content: string;
|
||||
content: AnnotationContent;
|
||||
value: string;
|
||||
pageNumber: number;
|
||||
dictionaryOperation = false;
|
||||
@ -78,7 +84,10 @@ export class AnnotationWrapper implements IListable {
|
||||
}
|
||||
|
||||
get isRedactedImageHint() {
|
||||
return this.IMAGE_HINT && this.superType === SuperTypes.Redaction;
|
||||
return (
|
||||
(this.IMAGE_HINT && this.superType === SuperTypes.Redaction) ||
|
||||
(this.IMAGE_HINT && this.superType === SuperTypes.ManualRedaction)
|
||||
);
|
||||
}
|
||||
|
||||
get isSkippedImageHint() {
|
||||
@ -103,7 +112,10 @@ export class AnnotationWrapper implements IListable {
|
||||
|
||||
get canBeMarkedAsFalsePositive() {
|
||||
return (
|
||||
(this.isRecommendation || this.superType === SuperTypes.Redaction || (this.isSkipped && this.isDictBased)) &&
|
||||
(this.isRecommendation ||
|
||||
this.superType === SuperTypes.Redaction ||
|
||||
(this.isSkipped && this.isDictBased) ||
|
||||
(this.isRemovedLocally && this.isDictBased)) &&
|
||||
!this.isImage &&
|
||||
!this.imported &&
|
||||
!this.pending &&
|
||||
@ -187,11 +199,11 @@ export class AnnotationWrapper implements IListable {
|
||||
}
|
||||
|
||||
get x() {
|
||||
return this.firstTopLeftPoint.x;
|
||||
return this.firstBottomLeftPoint.x;
|
||||
}
|
||||
|
||||
get y() {
|
||||
return this.firstTopLeftPoint.y;
|
||||
return this.firstBottomLeftPoint.y;
|
||||
}
|
||||
|
||||
get legalBasis() {
|
||||
@ -216,7 +228,7 @@ export class AnnotationWrapper implements IListable {
|
||||
annotationWrapper.value = 'Imported';
|
||||
annotationWrapper.color = earmark.hexColor;
|
||||
annotationWrapper.positions = earmark.positions;
|
||||
annotationWrapper.firstTopLeftPoint = earmark.positions[0]?.topLeft;
|
||||
annotationWrapper.firstBottomLeftPoint = earmark.positions[0]?.topLeft;
|
||||
annotationWrapper.superTypeLabel = annotationTypesTranslations[annotationWrapper.superType];
|
||||
|
||||
return annotationWrapper;
|
||||
@ -237,7 +249,7 @@ export class AnnotationWrapper implements IListable {
|
||||
annotationWrapper.isChangeLogEntry = logEntry.state === EntryStates.REMOVED || !!changeLogType;
|
||||
annotationWrapper.type = logEntry.type;
|
||||
annotationWrapper.value = logEntry.value;
|
||||
annotationWrapper.firstTopLeftPoint = { x: logEntry.positions[0].rectangle[0], y: logEntry.positions[0].rectangle[1] };
|
||||
annotationWrapper.firstBottomLeftPoint = { x: logEntry.positions[0].rectangle[0], y: logEntry.positions[0].rectangle[1] };
|
||||
annotationWrapper.pageNumber = logEntry.positions[0].pageNumber;
|
||||
annotationWrapper.positions = logEntry.positions.map(p => ({
|
||||
page: p.pageNumber,
|
||||
@ -279,7 +291,7 @@ export class AnnotationWrapper implements IListable {
|
||||
);
|
||||
|
||||
const content = this.#createContent(annotationWrapper, logEntry, isDocumine);
|
||||
annotationWrapper.shortContent = this.#getShortContent(annotationWrapper, legalBasisList) || content;
|
||||
annotationWrapper.shortContent = this.#getShortContent(annotationWrapper, legalBasisList) || content.untranslatedContent;
|
||||
annotationWrapper.content = content;
|
||||
|
||||
const lastRelevantManualChange = logEntry.manualChanges?.at(-1);
|
||||
@ -311,44 +323,62 @@ export class AnnotationWrapper implements IListable {
|
||||
}
|
||||
|
||||
static #createContent(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry, isDocumine: boolean) {
|
||||
let content = '';
|
||||
let untranslatedContent = '';
|
||||
const params: { [key: string]: string } = {};
|
||||
if (logEntry.matchedRule) {
|
||||
content += `Rule ${logEntry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`;
|
||||
params['hasRule'] = 'true';
|
||||
params['matchedRule'] = logEntry.matchedRule.replace(/(^[, ]*)|([, ]*$)/g, '');
|
||||
params['ruleSymbol'] = isDocumine ? ':' : '';
|
||||
|
||||
untranslatedContent += `Rule ${logEntry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`;
|
||||
}
|
||||
|
||||
if (logEntry.reason) {
|
||||
params['hasReason'] = 'true';
|
||||
if (isDocumine && logEntry.reason.slice(-1) === '.') {
|
||||
logEntry.reason = logEntry.reason.slice(0, -1);
|
||||
}
|
||||
|
||||
content += logEntry.reason + '\n\n';
|
||||
if (!params['hasRule']) {
|
||||
params['reason'] = logEntry.reason.substring(0, 1).toUpperCase() + logEntry.reason.substring(1);
|
||||
} else {
|
||||
params['reason'] = logEntry.reason;
|
||||
}
|
||||
params['reason'] = params['reason'].replace(/(^[, ]*)|([, ]*$)/g, '');
|
||||
untranslatedContent += logEntry.reason + '\n\n';
|
||||
//remove leading and trailing commas and whitespaces
|
||||
content = content.replace(/(^[, ]*)|([, ]*$)/g, '');
|
||||
content = content.substring(0, 1).toUpperCase() + content.substring(1);
|
||||
untranslatedContent = untranslatedContent.replace(/(^[, ]*)|([, ]*$)/g, '');
|
||||
untranslatedContent = untranslatedContent.substring(0, 1).toUpperCase() + untranslatedContent.substring(1);
|
||||
}
|
||||
|
||||
if (annotationWrapper.legalBasis && !isDocumine) {
|
||||
content += 'Legal basis: ' + annotationWrapper.legalBasis + '\n\n';
|
||||
params['hasLb'] = 'true';
|
||||
params['legalBasis'] = annotationWrapper.legalBasis;
|
||||
untranslatedContent += 'Legal basis: ' + annotationWrapper.legalBasis + '\n\n';
|
||||
}
|
||||
|
||||
if (annotationWrapper.hasBeenRemovedByManualOverride) {
|
||||
content += 'Removed by manual override';
|
||||
params['hasOverride'] = 'true';
|
||||
untranslatedContent += 'Removed by manual override';
|
||||
}
|
||||
|
||||
if (logEntry.section) {
|
||||
params['hasSection'] = 'true';
|
||||
params['sectionSymbol'] = isDocumine ? '' : ':';
|
||||
params['shouldLower'] = untranslatedContent.length.toString();
|
||||
params['section'] = logEntry.section;
|
||||
let prefix = `In section${isDocumine ? '' : ':'} `;
|
||||
if (content.length) {
|
||||
if (untranslatedContent.length) {
|
||||
prefix = ` ${prefix.toLowerCase()}`;
|
||||
}
|
||||
content += `${prefix} "${logEntry.section}"`;
|
||||
untranslatedContent += `${prefix} "${logEntry.section}"`;
|
||||
}
|
||||
|
||||
return content;
|
||||
return { translation: _('annotation-content'), params: params, untranslatedContent: untranslatedContent };
|
||||
}
|
||||
|
||||
static #getShortContent(annotationWrapper: AnnotationWrapper, legalBasisList: ILegalBasis[]) {
|
||||
if (annotationWrapper.legalBasis) {
|
||||
const lb = legalBasisList.find(lbm => lbm.reason?.toLowerCase().includes(annotationWrapper.legalBasis.toLowerCase()));
|
||||
const lb = legalBasisList.find(lbm => lbm.technicalName?.toLowerCase().includes(annotationWrapper.legalBasis.toLowerCase()));
|
||||
if (lb) {
|
||||
return lb.name;
|
||||
}
|
||||
|
||||
@ -21,7 +21,6 @@ interface NavItem {
|
||||
templateUrl: './account-side-nav.component.html',
|
||||
styleUrls: ['./account-side-nav.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [SideNavComponent, TranslateModule, NgForOf, NgIf, RouterLinkActive, RouterLink],
|
||||
})
|
||||
export class AccountSideNavComponent {
|
||||
|
||||
@ -8,10 +8,11 @@
|
||||
<div class="content-container full-height">
|
||||
<div class="overlay-shadow"></div>
|
||||
<div [ngClass]="!isWarningsScreen && 'dialog'">
|
||||
<div *ngIf="!isWarningsScreen" class="dialog-header">
|
||||
<div class="heading-l" [translate]="translations[path]"></div>
|
||||
</div>
|
||||
|
||||
@if (!isWarningsScreen) {
|
||||
<div class="dialog-header">
|
||||
<div class="heading-l" [translate]="translations[path]"></div>
|
||||
</div>
|
||||
}
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewContainerRef } from '@angular/core';
|
||||
import { Router, RouterOutlet } from '@angular/router';
|
||||
import { accountTranslations } from '@translations/account-translations';
|
||||
import { NgClass, NgIf } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { AccountSideNavComponent } from '../account-side-nav/account-side-nav.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
@ -10,8 +10,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
templateUrl: './base-account-screen-component.html',
|
||||
styleUrls: ['./base-account-screen-component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgClass, NgIf, RouterOutlet, AccountSideNavComponent, TranslateModule],
|
||||
imports: [NgClass, RouterOutlet, AccountSideNavComponent, TranslateModule],
|
||||
})
|
||||
export class BaseAccountScreenComponent implements OnInit {
|
||||
readonly translations = accountTranslations;
|
||||
|
||||
@ -25,7 +25,6 @@ const RSS_EXCLUDED_SETTINGS = ['USER_PROMOTED_TO_APPROVER', 'USER_DEGRADED_TO_RE
|
||||
templateUrl: './notifications-screen.component.html',
|
||||
styleUrls: ['./notifications-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, NgForOf, MatSlideToggle, TranslateModule, NgIf, MatCheckbox, IconButtonComponent],
|
||||
})
|
||||
export class NotificationsScreenComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
@ -41,7 +41,6 @@ interface DefaultOptionsForm {
|
||||
selector: 'redaction-dialog-defaults',
|
||||
templateUrl: './dialog-defaults.component.html',
|
||||
styleUrl: './dialog-defaults.component.scss',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, TranslateModule, MatFormField, MatSelect, MatOption, NgForOf, MatCheckbox, NgIf, IconButtonComponent],
|
||||
})
|
||||
export class DialogDefaultsComponent extends BaseFormComponent {
|
||||
|
||||
@ -31,6 +31,11 @@
|
||||
{{ 'preferences-screen.form.help-mode-dialog' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="overwriteFileOption">
|
||||
{{ 'preferences-screen.form.overwrite-file-option' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import {
|
||||
@ -27,6 +27,7 @@ interface PreferencesForm {
|
||||
// warnings preferences
|
||||
loadAllAnnotationsWarning: boolean;
|
||||
helpModeDialog: boolean;
|
||||
overwriteFileOption: boolean;
|
||||
|
||||
[k: string]: any;
|
||||
}
|
||||
@ -43,7 +44,6 @@ const Screens = {
|
||||
templateUrl: './preferences.component.html',
|
||||
styleUrls: ['./preferences.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
DialogDefaultsComponent,
|
||||
NgClass,
|
||||
@ -57,6 +57,12 @@ const Screens = {
|
||||
],
|
||||
})
|
||||
export class PreferencesComponent extends BaseFormComponent implements OnInit {
|
||||
readonly #formBuilder = inject(FormBuilder);
|
||||
readonly #permissionsService = inject(IqserPermissionsService);
|
||||
readonly #changeRef = inject(ChangeDetectorRef);
|
||||
readonly #loadingService = inject(LoadingService);
|
||||
readonly #userPreferenceService = inject(UserPreferenceService);
|
||||
|
||||
readonly form: FormGroup<AsControl<PreferencesForm>>;
|
||||
readonly currentScreen: Screen;
|
||||
readonly screens = Screens;
|
||||
@ -65,76 +71,87 @@ export class PreferencesComponent extends BaseFormComponent implements OnInit {
|
||||
readonly config = getConfig();
|
||||
readonly isIqserDevMode = isIqserDevMode();
|
||||
|
||||
constructor(
|
||||
route: ActivatedRoute,
|
||||
readonly userPreferenceService: UserPreferenceService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _permissionsService: IqserPermissionsService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
private readonly _loadingService: LoadingService,
|
||||
) {
|
||||
get #isOverwriteFileOptionActive() {
|
||||
return !(this.#userPreferenceService.getOverwriteFileOption() === 'undefined');
|
||||
}
|
||||
|
||||
constructor(route: ActivatedRoute) {
|
||||
super();
|
||||
this.form = this._formBuilder.group({
|
||||
this.form = this.#formBuilder.group({
|
||||
// preferences
|
||||
autoExpandFiltersOnActions: [this.userPreferenceService.getAutoExpandFiltersOnActions()],
|
||||
tableExtractionType: [this.userPreferenceService.getTableExtractionType()],
|
||||
autoExpandFiltersOnActions: [this.#userPreferenceService.getAutoExpandFiltersOnActions()],
|
||||
tableExtractionType: [this.#userPreferenceService.getTableExtractionType()],
|
||||
// warnings preferences
|
||||
loadAllAnnotationsWarning: [this.userPreferenceService.getBool(PreferencesKeys.loadAllAnnotationsWarning)],
|
||||
helpModeDialog: [this.userPreferenceService.getBool(KEYS.helpModeDialog)],
|
||||
loadAllAnnotationsWarning: [this.#userPreferenceService.getBool(PreferencesKeys.loadAllAnnotationsWarning)],
|
||||
helpModeDialog: [this.#userPreferenceService.getBool(KEYS.helpModeDialog)],
|
||||
overwriteFileOption: [this.#isOverwriteFileOptionActive],
|
||||
});
|
||||
|
||||
if (!this._permissionsService.has(Roles.managePreferences)) {
|
||||
if (!this.#permissionsService.has(Roles.managePreferences)) {
|
||||
this.form.disable();
|
||||
}
|
||||
|
||||
if (!this._permissionsService.has(Roles.getTables)) {
|
||||
if (!this.#permissionsService.has(Roles.getTables)) {
|
||||
this.form.controls.tableExtractionType.disable();
|
||||
}
|
||||
|
||||
if (!this.#isOverwriteFileOptionActive) {
|
||||
this.form.controls.overwriteFileOption.disable();
|
||||
}
|
||||
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this.currentScreen = route.snapshot.data.screen;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._loadingService.stop();
|
||||
this.#loadingService.stop();
|
||||
}
|
||||
|
||||
async save(): Promise<any> {
|
||||
if (this.form.controls.autoExpandFiltersOnActions.value !== this.userPreferenceService.getAutoExpandFiltersOnActions()) {
|
||||
await this.userPreferenceService.toggleAutoExpandFiltersOnActions();
|
||||
if (this.form.controls.autoExpandFiltersOnActions.value !== this.#userPreferenceService.getAutoExpandFiltersOnActions()) {
|
||||
await this.#userPreferenceService.toggleAutoExpandFiltersOnActions();
|
||||
}
|
||||
|
||||
if (this.form.controls.tableExtractionType.value !== this.userPreferenceService.getTableExtractionType()) {
|
||||
await this.userPreferenceService.save(PreferencesKeys.tableExtractionType, this.form.controls.tableExtractionType.value);
|
||||
if (this.form.controls.tableExtractionType.value !== this.#userPreferenceService.getTableExtractionType()) {
|
||||
await this.#userPreferenceService.save(PreferencesKeys.tableExtractionType, this.form.controls.tableExtractionType.value);
|
||||
}
|
||||
|
||||
if (
|
||||
this.form.controls.loadAllAnnotationsWarning.value !==
|
||||
this.userPreferenceService.getBool(PreferencesKeys.loadAllAnnotationsWarning)
|
||||
this.#userPreferenceService.getBool(PreferencesKeys.loadAllAnnotationsWarning)
|
||||
) {
|
||||
await this.userPreferenceService.save(
|
||||
await this.#userPreferenceService.save(
|
||||
PreferencesKeys.loadAllAnnotationsWarning,
|
||||
String(this.form.controls.loadAllAnnotationsWarning.value),
|
||||
);
|
||||
}
|
||||
|
||||
if (this.form.controls.helpModeDialog.value !== this.userPreferenceService.getBool(KEYS.helpModeDialog)) {
|
||||
await this.userPreferenceService.save(KEYS.helpModeDialog, String(this.form.controls.helpModeDialog.value));
|
||||
if (this.form.controls.helpModeDialog.value !== this.#userPreferenceService.getBool(KEYS.helpModeDialog)) {
|
||||
await this.#userPreferenceService.save(KEYS.helpModeDialog, String(this.form.controls.helpModeDialog.value));
|
||||
}
|
||||
|
||||
await this.userPreferenceService.reload();
|
||||
if (this.form.controls.overwriteFileOption.enabled && !this.form.controls.overwriteFileOption.value) {
|
||||
await this.#userPreferenceService.saveOverwriteFileOption('undefined');
|
||||
}
|
||||
|
||||
await this.#userPreferenceService.reload();
|
||||
this.#patchValues();
|
||||
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this._changeRef.markForCheck();
|
||||
this.#changeRef.markForCheck();
|
||||
}
|
||||
|
||||
#patchValues() {
|
||||
this.form.patchValue({
|
||||
autoExpandFiltersOnActions: this.userPreferenceService.getAutoExpandFiltersOnActions(),
|
||||
tableExtractionType: this.userPreferenceService.getTableExtractionType(),
|
||||
loadAllAnnotationsWarning: this.userPreferenceService.getBool(PreferencesKeys.loadAllAnnotationsWarning),
|
||||
helpModeDialog: this.userPreferenceService.getBool(KEYS.helpModeDialog),
|
||||
autoExpandFiltersOnActions: this.#userPreferenceService.getAutoExpandFiltersOnActions(),
|
||||
tableExtractionType: this.#userPreferenceService.getTableExtractionType(),
|
||||
loadAllAnnotationsWarning: this.#userPreferenceService.getBool(PreferencesKeys.loadAllAnnotationsWarning),
|
||||
helpModeDialog: this.#userPreferenceService.getBool(KEYS.helpModeDialog),
|
||||
overwriteFileOption: this.#isOverwriteFileOptionActive,
|
||||
});
|
||||
|
||||
if (!this.#isOverwriteFileOptionActive) {
|
||||
this.form.controls.overwriteFileOption.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ interface FormType {
|
||||
|
||||
@Component({
|
||||
templateUrl: './confirm-password-dialog.component.html',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, IconButtonComponent, TranslateModule, CircleButtonComponent],
|
||||
})
|
||||
export class ConfirmPasswordDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -16,13 +16,16 @@
|
||||
<input formControlName="lastName" name="lastName" type="text" />
|
||||
</div>
|
||||
|
||||
<div *ngIf="devMode" class="iqser-input-group">
|
||||
<div class="iqser-input-group">
|
||||
<label [translate]="'top-bar.navigation-items.my-account.children.language.label'"></label>
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="language">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
{{ translations[language] | translate }}
|
||||
</mat-option>
|
||||
<mat-select-trigger>{{ languageSelectLabel() | translate }}</mat-select-trigger>
|
||||
@for (language of languages; track language) {
|
||||
<mat-option [value]="language">
|
||||
{{ translations[language] | translate }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@ -31,17 +34,19 @@
|
||||
<a (click)="resetPassword()" target="_blank"> {{ 'user-profile-screen.actions.change-password' | translate }}</a>
|
||||
</div>
|
||||
|
||||
<div *ngIf="devMode" class="iqser-input-group">
|
||||
<mat-slide-toggle color="primary" formControlName="darkTheme">
|
||||
{{ 'user-profile-screen.form.dark-theme' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
@if (devMode) {
|
||||
<div class="iqser-input-group">
|
||||
<mat-slide-toggle color="primary" formControlName="darkTheme">
|
||||
{{ 'user-profile-screen.form.dark-theme' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<iqser-icon-button
|
||||
[disabled]="form.invalid || !(profileChanged || languageChanged || themeChanged)"
|
||||
[disabled]="disabled"
|
||||
[label]="'user-profile-screen.actions.save' | translate"
|
||||
[submit]="true"
|
||||
[type]="iconButtonTypes.primary"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed } from '@angular/core';
|
||||
import { FormGroup, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import {
|
||||
BaseFormComponent,
|
||||
@ -17,23 +17,47 @@ import { UserPreferenceService } from '@users/user-preference.service';
|
||||
import { UserService } from '@users/user.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { UserProfileDialogService } from '../services/user-profile-dialog.service';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MatOption, MatSelect } from '@angular/material/select';
|
||||
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||
import { PdfViewer } from '../../../../pdf-viewer/services/pdf-viewer.service';
|
||||
import { formControlToSignal } from '@utils/functions';
|
||||
import { AsControl } from '@common-ui/utils';
|
||||
|
||||
interface UserProfileForm {
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
language: string;
|
||||
darkTheme: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: './user-profile-screen.component.html',
|
||||
styleUrls: ['./user-profile-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, NgIf, MatFormField, MatSelect, MatOption, NgForOf, TranslateModule, MatSlideToggle, IconButtonComponent],
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
MatFormField,
|
||||
MatSelect,
|
||||
MatOption,
|
||||
TranslateModule,
|
||||
MatSlideToggle,
|
||||
IconButtonComponent,
|
||||
MatSelectTrigger,
|
||||
],
|
||||
})
|
||||
export class UserProfileScreenComponent extends BaseFormComponent implements OnInit {
|
||||
#profileModel: IProfile;
|
||||
export class UserProfileScreenComponent extends BaseFormComponent {
|
||||
readonly form: FormGroup<AsControl<UserProfileForm>> = this.#getForm();
|
||||
initialFormValue = this.form.getRawValue();
|
||||
readonly translations = languagesTranslations;
|
||||
readonly devMode = this._userPreferenceService.isIqserDevMode;
|
||||
|
||||
readonly profileKeys = ['email', 'firstName', 'lastName'];
|
||||
readonly languages = this._translateService.langs;
|
||||
readonly language = formControlToSignal<UserProfileForm['language']>(this.form.controls.language);
|
||||
readonly languageSelectLabel = computed(() => this.translations[this.language()]);
|
||||
|
||||
constructor(
|
||||
private readonly _userService: UserService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
@ -45,43 +69,29 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
|
||||
protected readonly _userPreferenceService: UserPreferenceService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _pdfViewer: PdfViewer,
|
||||
) {
|
||||
super();
|
||||
this._loadingService.start();
|
||||
if (!this._permissionsService.has(Roles.updateMyProfile)) {
|
||||
this.form.disable();
|
||||
}
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
get languageChanged(): boolean {
|
||||
return this.#profileModel['language'] !== this.form.get('language').value;
|
||||
return this.initialFormValue['language'] !== this.form.controls.language.value;
|
||||
}
|
||||
|
||||
get themeChanged(): boolean {
|
||||
return this.#profileModel['darkTheme'] !== this.form.get('darkTheme').value;
|
||||
return this.initialFormValue['darkTheme'] !== this.form.controls.darkTheme.value;
|
||||
}
|
||||
|
||||
get emailChanged(): boolean {
|
||||
return this.#profileModel['email'] !== this.form.get('email').value;
|
||||
return this.initialFormValue['email'] !== this.form.controls.email.value;
|
||||
}
|
||||
|
||||
get profileChanged(): boolean {
|
||||
const keys = Object.keys(this.form.getRawValue());
|
||||
keys.splice(keys.indexOf('language'), 1);
|
||||
keys.splice(keys.indexOf('darkTheme'), 1);
|
||||
|
||||
for (const key of keys) {
|
||||
if (this.#profileModel[key] !== this.form.get(key).value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get languages(): string[] {
|
||||
return this._translateService.langs;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._initializeForm();
|
||||
return this.profileKeys.some(key => this.initialFormValue[key] !== this.form.get(key).value);
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
@ -106,15 +116,17 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
|
||||
}
|
||||
|
||||
if (this.languageChanged) {
|
||||
await this._languageService.change(this.form.get('language').value);
|
||||
await this._languageService.change(this.form.controls.language.value);
|
||||
await this._pdfViewer.instance?.UI.setLanguage(this._languageService.currentLanguage);
|
||||
}
|
||||
|
||||
if (this.themeChanged) {
|
||||
await this._userPreferenceService.saveTheme(this.form.get('darkTheme').value ? 'dark' : 'light');
|
||||
await this._userPreferenceService.saveTheme(this.form.controls.darkTheme.value ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
this._initializeForm();
|
||||
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this._changeRef.markForCheck();
|
||||
this._loadingService.stop();
|
||||
this._toaster.success(_('user-profile-screen.update.success'));
|
||||
} catch (e) {
|
||||
this._loadingService.stop();
|
||||
@ -125,35 +137,13 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
|
||||
await this._userService.createResetPasswordAction();
|
||||
}
|
||||
|
||||
private _getForm(): UntypedFormGroup {
|
||||
#getForm() {
|
||||
return this._formBuilder.group({
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
firstName: [''],
|
||||
lastName: [''],
|
||||
language: [''],
|
||||
darkTheme: [false],
|
||||
email: [this._userService.currentUser.email ?? '', [Validators.required, Validators.email]],
|
||||
firstName: [this._userService.currentUser.firstName ?? ''],
|
||||
lastName: [this._userService.currentUser.lastName ?? ''],
|
||||
language: [this._userPreferenceService.getLanguage()],
|
||||
darkTheme: [this._userPreferenceService.getTheme() === 'dark'],
|
||||
});
|
||||
}
|
||||
|
||||
private _initializeForm(): void {
|
||||
try {
|
||||
this.form = this._getForm();
|
||||
if (!this._permissionsService.has(Roles.updateMyProfile)) {
|
||||
this.form.disable();
|
||||
}
|
||||
this.#profileModel = {
|
||||
email: this._userService.currentUser.email ?? '',
|
||||
firstName: this._userService.currentUser.firstName ?? '',
|
||||
lastName: this._userService.currentUser.lastName ?? '',
|
||||
language: this._languageService.currentLanguage ?? '',
|
||||
darkTheme: this._userPreferenceService.getTheme() === 'dark',
|
||||
};
|
||||
this.form.patchValue(this.#profileModel, { emitEvent: false });
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
this._loadingService.stop();
|
||||
this._changeRef.markForCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,18 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { addHintTranslations } from '@translations/add-hint-translations';
|
||||
import { redactTextTranslations } from '@translations/redact-text-translations';
|
||||
import { removeRedactionTranslations } from '@translations/remove-redaction-translations';
|
||||
import { RedactOrHintOptions, RemoveRedactionOptions } from '../../file-preview/utils/dialog-types';
|
||||
import {
|
||||
ForceAnnotationOptions,
|
||||
RectangleRedactOptions,
|
||||
RedactOrHintOptions,
|
||||
RemoveRedactionOptions,
|
||||
} from '../../file-preview/utils/dialog-types';
|
||||
|
||||
export const SystemDefaults = {
|
||||
RECTANGLE_REDACT_DEFAULT: RectangleRedactOptions.ONLY_THIS_PAGE,
|
||||
ADD_REDACTION_DEFAULT: RedactOrHintOptions.IN_DOSSIER,
|
||||
ADD_HINT_DEFAULT: RedactOrHintOptions.IN_DOSSIER,
|
||||
FORCE_REDACTION_DEFAULT: ForceAnnotationOptions.ONLY_HERE,
|
||||
REMOVE_REDACTION_DEFAULT: RemoveRedactionOptions.ONLY_HERE,
|
||||
REMOVE_HINT_DEFAULT: RemoveRedactionOptions.ONLY_HERE,
|
||||
REMOVE_RECOMMENDATION_DEFAULT: RemoveRedactionOptions.DO_NOT_RECOMMEND,
|
||||
@ -28,6 +35,10 @@ export const redactionAddOptions = [
|
||||
label: redactTextTranslations.onlyHere.label,
|
||||
value: RedactOrHintOptions.ONLY_HERE,
|
||||
},
|
||||
{
|
||||
label: redactTextTranslations.inDocument.label,
|
||||
value: RedactOrHintOptions.IN_DOCUMENT,
|
||||
},
|
||||
{
|
||||
label: redactTextTranslations.inDossier.label,
|
||||
value: RedactOrHintOptions.IN_DOSSIER,
|
||||
|
||||
@ -1,22 +1,24 @@
|
||||
import { CompositeRouteGuard, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui';
|
||||
import { RedRoleGuard } from '@users/red-role.guard';
|
||||
import { EntitiesListingScreenComponent } from './screens/entities-listing/entities-listing-screen.component';
|
||||
import { inject, provideEnvironmentInitializer } from '@angular/core';
|
||||
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
|
||||
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component';
|
||||
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
|
||||
import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component';
|
||||
import { templateExistsWhenEnteringAdmin } from '@guards/dossier-template-exists.guard';
|
||||
import { DossierTemplatesGuard } from '@guards/dossier-templates.guard';
|
||||
import { entityExistsGuard } from '@guards/entity-exists-guard.service';
|
||||
import { PermissionsGuard } from '@guards/permissions-guard';
|
||||
import { CompositeRouteGuard, IqserPermissionsGuard, IqserRoutes } from '@iqser/common-ui';
|
||||
import { IqserAuthGuard } from '@iqser/common-ui/lib/users';
|
||||
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain';
|
||||
import { CopilotService } from '@services/copilot.service';
|
||||
import { RedRoleGuard } from '@users/red-role.guard';
|
||||
import { Roles } from '@users/roles';
|
||||
import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component';
|
||||
import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component';
|
||||
import { DossierTemplatesGuard } from '@guards/dossier-templates.guard';
|
||||
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain';
|
||||
import { templateExistsWhenEnteringAdmin } from '@guards/dossier-template-exists.guard';
|
||||
import { entityExistsGuard } from '@guards/entity-exists-guard.service';
|
||||
import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component';
|
||||
import { PermissionsGuard } from '@guards/permissions-guard';
|
||||
import { Roles } from '@users/roles';
|
||||
import { IqserAuthGuard } from '@iqser/common-ui/lib/users';
|
||||
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
|
||||
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
|
||||
import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component';
|
||||
import { EntitiesListingScreenComponent } from './screens/entities-listing/entities-listing-screen.component';
|
||||
import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { AdminDialogService } from './services/admin-dialog.service';
|
||||
import { AuditService } from './services/audit.service';
|
||||
import { DigitalSignatureService } from './services/digital-signature.service';
|
||||
@ -78,7 +80,12 @@ const dossierTemplateIdRoutes: IqserRoutes = [
|
||||
},
|
||||
type: 'ENTITY',
|
||||
},
|
||||
providers: [RulesService],
|
||||
providers: [
|
||||
RulesService,
|
||||
provideEnvironmentInitializer(() => {
|
||||
return inject(CopilotService).connectAsync('/api/llm/llm-websocket');
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'component-rules',
|
||||
|
||||
@ -5,7 +5,6 @@ import { RouterOutlet } from '@angular/router';
|
||||
@Component({
|
||||
templateUrl: './base-admin-screen.component.html',
|
||||
styleUrls: ['./base-admin-screen.component.scss'],
|
||||
standalone: true,
|
||||
imports: [AdminSideNavComponent, RouterOutlet],
|
||||
})
|
||||
export class BaseAdminScreenComponent {}
|
||||
|
||||
@ -9,7 +9,6 @@ import { AdminSideNavComponent } from '../shared/components/admin-side-nav/admin
|
||||
@Component({
|
||||
templateUrl: './base-dossier-template-screen.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
DossierTemplateBreadcrumbsComponent,
|
||||
DossierTemplateActionsComponent,
|
||||
|
||||
@ -18,7 +18,6 @@ import { AdminSideNavComponent } from '../shared/components/admin-side-nav/admin
|
||||
@Component({
|
||||
templateUrl: './base-entity-screen.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
DossierTemplateBreadcrumbsComponent,
|
||||
CircleButtonComponent,
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
<div class="mt-44">
|
||||
<redaction-donut-chart
|
||||
[config]="chartConfig"
|
||||
[config]="chartConfig()"
|
||||
[radius]="63"
|
||||
[strokeWidth]="15"
|
||||
[subtitles]="['user-stats.chart.users' | translate]"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, input, Input, output, Output } from '@angular/core';
|
||||
import { DonutChartConfig } from '@red/domain';
|
||||
import { CircleButtonComponent } from '@iqser/common-ui';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
@ -8,10 +8,9 @@ import { DonutChartComponent } from '@shared/components/donut-chart/donut-chart.
|
||||
selector: 'redaction-users-stats',
|
||||
templateUrl: './users-stats.component.html',
|
||||
styleUrls: ['./users-stats.component.scss'],
|
||||
standalone: true,
|
||||
imports: [CircleButtonComponent, TranslateModule, DonutChartComponent],
|
||||
})
|
||||
export class UsersStatsComponent {
|
||||
@Output() toggleCollapse = new EventEmitter();
|
||||
@Input() chartConfig: DonutChartConfig[];
|
||||
readonly chartConfig = input.required<DonutChartConfig[]>();
|
||||
readonly toggleCollapse = output();
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ export interface CloneTemplateData {
|
||||
@Component({
|
||||
templateUrl: './add-clone-dossier-template-dialog.component.html',
|
||||
styleUrls: ['./add-clone-dossier-template-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [TranslateModule, ReactiveFormsModule, IconButtonComponent, CircleButtonComponent],
|
||||
})
|
||||
export class AddCloneDossierTemplateDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -8,7 +8,6 @@ import { UserDetailsComponent } from './user-details/user-details.component';
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-user-dialog',
|
||||
templateUrl: './add-edit-user-dialog.component.html',
|
||||
standalone: true,
|
||||
imports: [UserDetailsComponent, ResetPasswordComponent, CircleButtonComponent],
|
||||
})
|
||||
export class AddEditUserDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -10,7 +10,6 @@ import { NamePipe } from '@common-ui/users/name.pipe';
|
||||
@Component({
|
||||
selector: 'redaction-reset-password',
|
||||
templateUrl: './reset-password.component.html',
|
||||
standalone: true,
|
||||
imports: [TranslateModule, NamePipe, ReactiveFormsModule, IconButtonComponent],
|
||||
})
|
||||
export class ResetPasswordComponent {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div
|
||||
[translateParams]="{
|
||||
type: user ? 'edit' : 'create'
|
||||
type: !!user() ? 'edit' : 'create',
|
||||
}"
|
||||
[translate]="'add-edit-user.title'"
|
||||
class="dialog-header heading-l"
|
||||
@ -32,14 +32,22 @@
|
||||
[formControlName]="role"
|
||||
color="primary"
|
||||
>
|
||||
{{ translations[role] | translate }}
|
||||
{{ translations[role] | translate: { count: 1 } }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (!user()) {
|
||||
<div class="iqser-input-group">
|
||||
<label [translate]="'add-edit-user.form.account-setup'"></label>
|
||||
<mat-checkbox formControlName="sendSetPasswordMail">{{ 'add-edit-user.form.send-email' | translate }}</mat-checkbox>
|
||||
<span [translate]="'add-edit-user.form.send-email-explanation'" class="hint"></span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div
|
||||
(click)="toggleResetPassword.emit()"
|
||||
*ngIf="!!user"
|
||||
*ngIf="!!user()"
|
||||
[translate]="'add-edit-user.form.reset-password'"
|
||||
class="mt-24 fit-content link-action"
|
||||
></div>
|
||||
@ -48,14 +56,14 @@
|
||||
<div class="dialog-actions">
|
||||
<iqser-icon-button
|
||||
[disabled]="form.invalid || !changed"
|
||||
[label]="(user ? 'add-edit-user.actions.save-changes' : 'add-edit-user.actions.save') | translate"
|
||||
[label]="(user() ? 'add-edit-user.actions.save-changes' : 'add-edit-user.actions.save') | translate"
|
||||
[submit]="true"
|
||||
[type]="iconButtonTypes.primary"
|
||||
></iqser-icon-button>
|
||||
|
||||
<iqser-icon-button
|
||||
(action)="delete()"
|
||||
*ngIf="user && !disabledDelete(user)"
|
||||
*ngIf="user() && !disabledDelete(user())"
|
||||
[label]="'add-edit-user.actions.delete' | translate"
|
||||
[type]="iconButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
|
||||
@ -5,3 +5,7 @@
|
||||
margin-top: 8px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-left: 23px;
|
||||
}
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
|
||||
import { Component, input, OnInit, output } from '@angular/core';
|
||||
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { AdminDialogService } from '../../../services/admin-dialog.service';
|
||||
import { BaseFormComponent, IconButtonComponent, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { rolesTranslations } from '@translations/roles-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { User } from '@red/domain';
|
||||
import { UserService } from '@users/user.service';
|
||||
import { HttpStatusCode } from '@angular/common/http';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { IProfileUpdateRequest } from '@iqser/common-ui/lib/users';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
@ -17,18 +15,17 @@ import { NgForOf, NgIf } from '@angular/common';
|
||||
selector: 'redaction-user-details',
|
||||
templateUrl: './user-details.component.html',
|
||||
styleUrls: ['./user-details.component.scss'],
|
||||
standalone: true,
|
||||
imports: [TranslateModule, ReactiveFormsModule, MatCheckbox, NgForOf, IconButtonComponent, NgIf],
|
||||
})
|
||||
export class UserDetailsComponent extends BaseFormComponent implements OnChanges {
|
||||
/** e.g. a RED_ADMIN is automatically a RED_USER_ADMIN => can't disable RED_USER_ADMIN as long as RED_ADMIN is checked */
|
||||
private readonly _ROLE_REQUIREMENTS = { RED_MANAGER: 'RED_USER', RED_ADMIN: 'RED_USER_ADMIN' };
|
||||
@Input() user: User;
|
||||
@Output() readonly toggleResetPassword = new EventEmitter();
|
||||
@Output() readonly closeDialog = new EventEmitter();
|
||||
@Output() readonly cancel = new EventEmitter();
|
||||
export class UserDetailsComponent extends BaseFormComponent implements OnInit {
|
||||
user = input<User>();
|
||||
readonly toggleResetPassword = output();
|
||||
readonly closeDialog = output<boolean>();
|
||||
readonly cancel = output();
|
||||
readonly ROLES = ['RED_USER', 'RED_MANAGER', 'RED_USER_ADMIN', 'RED_ADMIN'];
|
||||
readonly translations = rolesTranslations;
|
||||
/** e.g. a RED_ADMIN is automatically a RED_USER_ADMIN => can't disable RED_USER_ADMIN as long as RED_ADMIN is checked */
|
||||
readonly #ROLE_REQUIREMENTS = { RED_MANAGER: 'RED_USER', RED_ADMIN: 'RED_USER_ADMIN' };
|
||||
|
||||
constructor(
|
||||
private readonly _formBuilder: UntypedFormBuilder,
|
||||
@ -49,13 +46,17 @@ export class UserDetailsComponent extends BaseFormComponent implements OnChanges
|
||||
}, []);
|
||||
}
|
||||
|
||||
private get _rolesControls(): any {
|
||||
get sendSetPasswordMail() {
|
||||
return !this.form.controls.sendSetPasswordMail.value;
|
||||
}
|
||||
|
||||
get #rolesControls() {
|
||||
return this.ROLES.reduce(
|
||||
(prev, role) => ({
|
||||
...prev,
|
||||
[role]: [
|
||||
{
|
||||
value: this.user && this.user.has(role),
|
||||
value: this.user() && this.user().has(role),
|
||||
disabled: this.shouldBeDisabled(role),
|
||||
},
|
||||
],
|
||||
@ -64,20 +65,20 @@ export class UserDetailsComponent extends BaseFormComponent implements OnChanges
|
||||
);
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.form = this._getForm();
|
||||
ngOnInit() {
|
||||
this.form = this.#getForm();
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
shouldBeDisabled(role: string): boolean {
|
||||
const isCurrentAdminUser = this.user && this.user.isAdmin && this.user.id === this._userService.currentUser.id;
|
||||
const isCurrentAdminUser = this.user() && this.user().isAdmin && this.user().id === this._userService.currentUser.id;
|
||||
return (
|
||||
// RED_ADMIN can't remove own RED_ADMIN role
|
||||
(role === 'RED_ADMIN' && isCurrentAdminUser) ||
|
||||
// only RED_ADMINs can edit RED_ADMIN roles
|
||||
(role === 'RED_ADMIN' && !this._userService.currentUser.isAdmin) ||
|
||||
Object.keys(this._ROLE_REQUIREMENTS).reduce(
|
||||
(value, key) => value || (role === this._ROLE_REQUIREMENTS[key] && this.user?.roles.includes(key)),
|
||||
Object.keys(this.#ROLE_REQUIREMENTS).reduce(
|
||||
(value, key) => value || (role === this.#ROLE_REQUIREMENTS[key] && this.user()?.roles.includes(key)),
|
||||
false,
|
||||
)
|
||||
);
|
||||
@ -85,38 +86,38 @@ export class UserDetailsComponent extends BaseFormComponent implements OnChanges
|
||||
|
||||
async save() {
|
||||
this._loadingService.start();
|
||||
const userData: IProfileUpdateRequest = { ...this.form.getRawValue(), roles: this.activeRoles };
|
||||
const userData: IProfileUpdateRequest = {
|
||||
...this.form.getRawValue(),
|
||||
roles: this.activeRoles,
|
||||
sendSetPasswordMail: this.sendSetPasswordMail,
|
||||
};
|
||||
|
||||
if (!this.user) {
|
||||
if (!this.user()) {
|
||||
await firstValueFrom(this._userService.create(userData))
|
||||
.then(() => {
|
||||
this.closeDialog.emit(true);
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status === HttpStatusCode.Conflict) {
|
||||
this._toaster.error(_('add-edit-user.error.email-already-used'));
|
||||
} else {
|
||||
this._toaster.error(_('add-edit-user.error.generic'));
|
||||
}
|
||||
this._toaster.error(null, { error });
|
||||
this._loadingService.stop();
|
||||
});
|
||||
} else {
|
||||
await firstValueFrom(this._userService.updateProfile(userData, this.user.id));
|
||||
await firstValueFrom(this._userService.updateProfile(userData, this.user().id));
|
||||
this.closeDialog.emit(true);
|
||||
}
|
||||
}
|
||||
|
||||
delete() {
|
||||
this._dialogService.deleteUsers([this.user.id], () => this.closeDialog.emit(true));
|
||||
this._dialogService.deleteUsers([this.user().id], () => this.closeDialog.emit(true));
|
||||
}
|
||||
|
||||
setRolesRequirements(checked: boolean, role: string): void {
|
||||
if (Object.keys(this._ROLE_REQUIREMENTS).includes(role)) {
|
||||
if (Object.keys(this.#ROLE_REQUIREMENTS).includes(role)) {
|
||||
if (checked) {
|
||||
this.form.patchValue({ [this._ROLE_REQUIREMENTS[role]]: true });
|
||||
this.form.controls[this._ROLE_REQUIREMENTS[role]].disable();
|
||||
this.form.patchValue({ [this.#ROLE_REQUIREMENTS[role]]: true });
|
||||
this.form.controls[this.#ROLE_REQUIREMENTS[role]].disable();
|
||||
} else {
|
||||
this.form.controls[this._ROLE_REQUIREMENTS[role]].enable();
|
||||
this.form.controls[this.#ROLE_REQUIREMENTS[role]].enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,18 +128,19 @@ export class UserDetailsComponent extends BaseFormComponent implements OnChanges
|
||||
return user.id === this._userService.currentUser.id || (userAdmin && !currentUserAdmin);
|
||||
}
|
||||
|
||||
private _getForm(): UntypedFormGroup {
|
||||
#getForm(): UntypedFormGroup {
|
||||
return this._formBuilder.group({
|
||||
firstName: [this.user?.firstName, Validators.required],
|
||||
lastName: [this.user?.lastName, Validators.required],
|
||||
firstName: [this.user()?.firstName, Validators.required],
|
||||
lastName: [this.user()?.lastName, Validators.required],
|
||||
email: [
|
||||
{
|
||||
value: this.user?.email,
|
||||
disabled: !!this.user?.email,
|
||||
value: this.user()?.email,
|
||||
disabled: !!this.user()?.email,
|
||||
},
|
||||
[Validators.required, Validators.email],
|
||||
],
|
||||
...this._rolesControls,
|
||||
...this.#rolesControls,
|
||||
sendSetPasswordMail: [false],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ interface DialogData {
|
||||
@Component({
|
||||
templateUrl: './add-entity-dialog.component.html',
|
||||
styleUrls: ['./add-entity-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [AddEditEntityComponent, TranslateModule, IconButtonComponent, NgIf, CircleButtonComponent, HelpButtonComponent],
|
||||
})
|
||||
export class AddEntityDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -6,9 +6,11 @@
|
||||
<div class="table-header">Key</div>
|
||||
<div class="table-header">Value</div>
|
||||
|
||||
<ng-container *ngFor="let entry of data.auditEntry.details | keyvalue : originalOrder">
|
||||
<ng-container *ngFor="let entry of data.auditEntry.details | keyvalue: originalOrder">
|
||||
<div class="bold">{{ entry.key | humanize }}</div>
|
||||
<div>{{ entry.value }}</div>
|
||||
<div>
|
||||
<pre>{{ entry.value | json }}</pre>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { KeyValue, KeyValuePipe, NgForOf } from '@angular/common';
|
||||
import { JsonPipe, KeyValue, KeyValuePipe, NgForOf } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { BaseDialogComponent, CircleButtonComponent, HumanizePipe } from '@iqser/common-ui';
|
||||
@ -16,8 +16,7 @@ type OrderFn = (a: KeyValue<string, string>, b: KeyValue<string, string>) => num
|
||||
templateUrl: './audit-info-dialog.component.html',
|
||||
styleUrls: ['./audit-info-dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [TranslateModule, NgForOf, KeyValuePipe, HumanizePipe, CircleButtonComponent],
|
||||
imports: [TranslateModule, NgForOf, KeyValuePipe, HumanizePipe, CircleButtonComponent, JsonPipe],
|
||||
})
|
||||
export class AuditInfoDialogComponent extends BaseDialogComponent {
|
||||
constructor(
|
||||
|
||||
@ -20,7 +20,6 @@ const KMS_SIGNATURE_DIALOG_WIDTH = '810px';
|
||||
@Component({
|
||||
templateUrl: './configure-certificate-dialog.component.html',
|
||||
styleUrls: ['./configure-certificate-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
DetailsRadioComponent,
|
||||
NgIf,
|
||||
|
||||
@ -13,7 +13,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
templateUrl: './kms-signature-configuration.component.html',
|
||||
styleUrls: ['./kms-signature-configuration.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [UploadFileComponent, ReactiveFormsModule, NgIf, TranslateModule],
|
||||
})
|
||||
export class KmsSignatureConfigurationComponent extends BaseSignatureConfigurationComponent implements OnInit {
|
||||
|
||||
@ -14,7 +14,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
templateUrl: './pkcs-signature-configuration.component.html',
|
||||
styleUrls: ['./pkcs-signature-configuration.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [UploadFileComponent, ReactiveFormsModule, NgIf, TranslateModule],
|
||||
})
|
||||
export class PkcsSignatureConfigurationComponent extends BaseSignatureConfigurationComponent implements OnInit {
|
||||
|
||||
@ -20,7 +20,6 @@ interface IEditColorData {
|
||||
@Component({
|
||||
templateUrl: './edit-color-dialog.component.html',
|
||||
styleUrls: ['./edit-color-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, TranslateModule, ColorPickerModule, MatIcon, NgIf, IconButtonComponent, CircleButtonComponent],
|
||||
})
|
||||
export class EditColorDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -9,7 +9,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
@Component({
|
||||
selector: 'redaction-smtp-auth-dialog',
|
||||
templateUrl: './smtp-auth-dialog.component.html',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, TranslateModule, IconButtonComponent, CircleButtonComponent, MatDialogClose],
|
||||
})
|
||||
export class SmtpAuthDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -7,7 +7,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
templateUrl: './upload-dictionary-dialog.component.html',
|
||||
styleUrls: ['./upload-dictionary-dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [IconButtonComponent, TranslateModule],
|
||||
})
|
||||
export class UploadDictionaryDialogComponent {
|
||||
|
||||
@ -17,7 +17,7 @@ import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { auditCategoriesTranslations } from '@translations/audit-categories-translations';
|
||||
import { Roles } from '@users/roles';
|
||||
import { applyIntervalConstraints } from '@utils/date-inputs-utils';
|
||||
import { Dayjs } from 'dayjs';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { AuditService } from '../../services/audit.service';
|
||||
@ -36,7 +36,6 @@ const PAGE_SIZE = 50;
|
||||
templateUrl: './audit-screen.component.html',
|
||||
styleUrls: ['./audit-screen.component.scss'],
|
||||
providers: listingProvidersFactory(AuditScreenComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
TranslateModule,
|
||||
@ -139,16 +138,9 @@ export class AuditScreenComponent extends ListingComponent<Audit> implements OnI
|
||||
const promises = [];
|
||||
const category = this.form.get('category').value;
|
||||
const userId = this.form.get('userId').value;
|
||||
const from = this.form.get('from').value;
|
||||
let to = this.form.get('to').value;
|
||||
if (to) {
|
||||
const hoursLeft = new Date(to).getHours();
|
||||
const minutesLeft = new Date(to).getMinutes();
|
||||
to = to
|
||||
.clone()
|
||||
.add(24 - hoursLeft - 1, 'h')
|
||||
.add(60 - minutesLeft - 1);
|
||||
}
|
||||
const from = this.form.get('from').value ? dayjs(this.form.get('from').value).startOf('day').toISOString() : null;
|
||||
const to = this.form.get('to').value ? dayjs(this.form.get('to').value).endOf('day').toISOString() : null;
|
||||
|
||||
const logsRequestBody: IAuditSearchRequest = {
|
||||
pageSize: PAGE_SIZE,
|
||||
page: page,
|
||||
|
||||
@ -50,9 +50,11 @@
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
}
|
||||
@if (selectedComponent?.id === component.id) {
|
||||
<mat-icon class="arrow-right" svgIcon="red:arrow-right"></mat-icon>
|
||||
}
|
||||
<mat-icon
|
||||
[class.not-visible]="selectedComponent?.id !== component.id"
|
||||
class="arrow-right"
|
||||
svgIcon="red:arrow-right"
|
||||
></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
|
||||
.arrow-right {
|
||||
transform: scale(0.7);
|
||||
|
||||
&.not-visible {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,6 +49,8 @@
|
||||
.content-container {
|
||||
background-color: var(--iqser-grey-6);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.content-header {
|
||||
display: flex;
|
||||
@ -61,6 +67,7 @@
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
overflow: hidden;
|
||||
@ -68,7 +75,8 @@
|
||||
.components-list {
|
||||
flex: 1;
|
||||
background-color: var(--iqser-white);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
height: 30px;
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
import { Component, OnInit, signal } from '@angular/core';
|
||||
import { BaseFormComponent, CircleButtonComponent, IconButtonComponent, listingProvidersFactory, LoadingService } from '@iqser/common-ui';
|
||||
import {
|
||||
BaseFormComponent,
|
||||
CircleButtonComponent,
|
||||
HasScrollbarDirective,
|
||||
IconButtonComponent,
|
||||
listingProvidersFactory,
|
||||
LoadingService,
|
||||
} from '@iqser/common-ui';
|
||||
import { ComponentDefinitionsService } from '@services/entity-services/component-definitions.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { getParam } from '@common-ui/utils';
|
||||
import { DOSSIER_TEMPLATE_ID, IComponentDefinition } from '@red/domain';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { InputWithActionComponent } from '@common-ui/inputs/input-with-action/input-with-action.component';
|
||||
import { CommonModule, NgIf } from '@angular/common';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
@ -18,11 +24,8 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
templateUrl: './component-definitions.component.html',
|
||||
styleUrls: ['./component-definitions.component.scss'],
|
||||
providers: listingProvidersFactory(ComponentDefinitionsComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IconButtonComponent,
|
||||
InputWithActionComponent,
|
||||
NgIf,
|
||||
TranslateModule,
|
||||
CommonModule,
|
||||
MatIcon,
|
||||
@ -32,6 +35,7 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
CircleButtonComponent,
|
||||
HasScrollbarDirective,
|
||||
],
|
||||
})
|
||||
export default class ComponentDefinitionsComponent extends BaseFormComponent implements OnInit {
|
||||
@ -103,6 +107,7 @@ export default class ComponentDefinitionsComponent extends BaseFormComponent imp
|
||||
this._dialogService.openDialog('confirm', null, async () => {
|
||||
await firstValueFrom(this._componentDefinitionsService.deleteComponentDefinitions(this.#dossierTemplateId, [componentId]));
|
||||
await this.#loadData();
|
||||
this.selectedComponent = null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<div
|
||||
class="row"
|
||||
[matTooltip]="'add-edit-component-mapping.disabled-file-options' | translate"
|
||||
[matTooltipDisabled]="!disabledFileOptions"
|
||||
[matTooltipDisabled]="!form.get('encoding')?.disabled"
|
||||
[matTooltipPosition]="'above'"
|
||||
>
|
||||
<div class="iqser-input-group required w-150">
|
||||
@ -40,13 +40,21 @@
|
||||
formControlName="delimiter"
|
||||
name="delimiter"
|
||||
type="text"
|
||||
[class.disabled-file-options]="disabledFileOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="iqser-input-group required w-150">
|
||||
<label translate="add-edit-component-mapping.form.quote-char"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-component-mapping.form.quote-char-placeholder' | translate"
|
||||
formControlName="quoteChar"
|
||||
name="quoteChar"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required w-150">
|
||||
<label translate="add-edit-component-mapping.form.encoding-type"></label>
|
||||
<mat-form-field [class.disabled-file-options]="disabledFileOptions">
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="encoding">
|
||||
<mat-option *ngFor="let type of encodingTypeOptions" [value]="type">
|
||||
{{ translations[type] | translate }}
|
||||
|
||||
@ -18,11 +18,6 @@
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled-file-options {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.row:last-child {
|
||||
|
||||
@ -7,7 +7,7 @@ import { NgForOf, NgIf } from '@angular/common';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatOption } from '@angular/material/autocomplete';
|
||||
import { MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import { fileAttributeEncodingTypesTranslations } from '@translations/file-attribute-encoding-types-translations';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { ComponentMappingsService } from '@services/entity-services/component-mappings.service';
|
||||
@ -17,19 +17,20 @@ interface DialogData {
|
||||
dossierTemplateId: string;
|
||||
mapping: IComponentMapping;
|
||||
}
|
||||
|
||||
interface DialogResult {
|
||||
id: string;
|
||||
name: string;
|
||||
file: Blob;
|
||||
encoding: string;
|
||||
delimiter: string;
|
||||
quoteChar: string;
|
||||
fileName?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: './add-edit-component-mapping-dialog.component.html',
|
||||
styleUrls: ['./add-edit-component-mapping-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
TranslateModule,
|
||||
ReactiveFormsModule,
|
||||
@ -39,7 +40,6 @@ interface DialogResult {
|
||||
CircleButtonComponent,
|
||||
MatDialogModule,
|
||||
MatOption,
|
||||
MatSelectTrigger,
|
||||
MatSelect,
|
||||
IconButtonComponent,
|
||||
UploadFileComponent,
|
||||
@ -52,7 +52,6 @@ export class AddEditComponentMappingDialogComponent
|
||||
{
|
||||
protected readonly encodingTypeOptions = Object.keys(FileAttributeEncodingTypes);
|
||||
protected readonly translations = fileAttributeEncodingTypesTranslations;
|
||||
#fileChanged = false;
|
||||
activeFile: File;
|
||||
form!: UntypedFormGroup;
|
||||
|
||||
@ -73,13 +72,14 @@ export class AddEditComponentMappingDialogComponent
|
||||
const file = new Blob([fileContent.body as Blob], { type: 'text/csv' });
|
||||
this.form.get('file').setValue(file);
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this.#disableEncodingAndQuoteCharAndDelimiter();
|
||||
}
|
||||
}
|
||||
|
||||
changeFile(file: File) {
|
||||
this.#fileChanged = true;
|
||||
this.form.get('file').setValue(file);
|
||||
this.form.get('fileName').setValue(file?.name);
|
||||
this.#enableEncodingAndQuoteCharAndDelimiter();
|
||||
}
|
||||
|
||||
save() {
|
||||
@ -93,10 +93,19 @@ export class AddEditComponentMappingDialogComponent
|
||||
fileName: [this.data?.mapping?.fileName, Validators.required],
|
||||
encoding: this.encodingTypeOptions.find(e => e === this.data?.mapping?.encoding) ?? this.encodingTypeOptions[0],
|
||||
delimiter: [this.data?.mapping?.delimiter ?? ',', Validators.required],
|
||||
quoteChar: [this.data?.mapping?.quoteChar ?? '"', Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
get disabledFileOptions() {
|
||||
return this.initialFormValue?.file && !this.#fileChanged;
|
||||
#disableEncodingAndQuoteCharAndDelimiter() {
|
||||
this.form.get('encoding').disable();
|
||||
this.form.get('delimiter').disable();
|
||||
this.form.get('quoteChar').disable();
|
||||
}
|
||||
|
||||
#enableEncodingAndQuoteCharAndDelimiter() {
|
||||
this.form.get('encoding').enable();
|
||||
this.form.get('delimiter').enable();
|
||||
this.form.get('quoteChar').enable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { InputWithActionComponent } from '@common-ui/inputs/input-with-action/input-with-action.component';
|
||||
import { getCurrentUser } from '@common-ui/users';
|
||||
@ -25,9 +24,6 @@ import { Roles } from '@users/roles';
|
||||
import { combineLatest, firstValueFrom } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { AdminSideNavComponent } from '../../shared/components/admin-side-nav/admin-side-nav.component';
|
||||
import { DossierTemplateActionsComponent } from '../../shared/components/dossier-template-actions/dossier-template-actions.component';
|
||||
import { DossierTemplateBreadcrumbsComponent } from '../../shared/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component';
|
||||
import { AddEditComponentMappingDialogComponent } from './add-edit-component-mapping-dialog/add-edit-component-mapping-dialog.component';
|
||||
import { download } from '@utils/file-download-utils';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
@ -36,16 +32,11 @@ import { MatTooltip } from '@angular/material/tooltip';
|
||||
templateUrl: './component-mappings-screen.component.html',
|
||||
styleUrls: ['./component-mappings-screen.component.scss'],
|
||||
providers: listingProvidersFactory(ComponentMappingsScreenComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
DossierTemplateBreadcrumbsComponent,
|
||||
AsyncPipe,
|
||||
NgIf,
|
||||
DossierTemplateActionsComponent,
|
||||
CircleButtonComponent,
|
||||
TranslateModule,
|
||||
RouterLink,
|
||||
AdminSideNavComponent,
|
||||
IqserListingModule,
|
||||
InputWithActionComponent,
|
||||
IconButtonComponent,
|
||||
@ -99,8 +90,8 @@ export default class ComponentMappingsScreenComponent extends ListingComponent<C
|
||||
const result = await dialog.result();
|
||||
if (result) {
|
||||
this._loadingService.start();
|
||||
const { id, name, encoding, delimiter, fileName } = result;
|
||||
const newMapping = { id, name, encoding, delimiter, fileName };
|
||||
const { id, name, encoding, delimiter, fileName, quoteChar } = result;
|
||||
const newMapping = { id, name, encoding, delimiter, fileName, quoteChar };
|
||||
await firstValueFrom(
|
||||
this._componentMappingService.createUpdateComponentMapping(this.#dossierTemplateId, newMapping, result.file),
|
||||
);
|
||||
|
||||
@ -33,7 +33,6 @@ interface ListItem extends IListable {
|
||||
styleUrls: ['./default-colors-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: listingProvidersFactory(DefaultColorsScreenComponent),
|
||||
standalone: true,
|
||||
imports: [IqserListingModule, NgStyle, CircleButtonComponent, IqserAllowDirective, TranslateModule, AsyncPipe, NgIf],
|
||||
})
|
||||
export class DefaultColorsScreenComponent extends ListingComponent<ListItem> implements OnInit {
|
||||
|
||||
@ -25,7 +25,6 @@ import { DigitalSignatureService } from '../../services/digital-signature.servic
|
||||
selector: 'redaction-digital-signature-screen',
|
||||
templateUrl: './digital-signature-screen.component.html',
|
||||
styleUrls: ['./digital-signature-screen.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
EmptyStateComponent,
|
||||
|
||||
@ -20,7 +20,6 @@ export interface AddEditDossierAttributeDialogData {
|
||||
@Component({
|
||||
templateUrl: './add-edit-dossier-attribute-dialog.component.html',
|
||||
styleUrls: ['./add-edit-dossier-attribute-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
TranslateModule,
|
||||
ReactiveFormsModule,
|
||||
@ -91,7 +90,7 @@ export class AddEditDossierAttributeDialogComponent extends BaseDialogComponent
|
||||
const createOrUpdate = this._dossierAttributesService.createOrUpdate(attribute, this.data.dossierTemplateId);
|
||||
const result = await createOrUpdate.catch((error: HttpErrorResponse) => {
|
||||
this._loadingService.stop();
|
||||
this._toaster.error(_('add-edit-dossier-attribute.error.generic'), { error });
|
||||
this._toaster.rawError(error.error.message);
|
||||
return undefined;
|
||||
});
|
||||
|
||||
|
||||
@ -35,7 +35,6 @@ import { TableItemComponent } from './table-item/table-item.component';
|
||||
entitiesService: DossierAttributesService,
|
||||
component: DossierAttributesListingScreenComponent,
|
||||
}),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
TranslateModule,
|
||||
|
||||
@ -10,7 +10,6 @@ import { NgIf } from '@angular/common';
|
||||
selector: 'redaction-table-item [attribute] [canEditDossierAttributes]',
|
||||
templateUrl: './table-item.component.html',
|
||||
styleUrls: ['./table-item.component.scss'],
|
||||
standalone: true,
|
||||
imports: [MatTooltip, TranslateModule, CircleButtonComponent, NgIf],
|
||||
})
|
||||
export class TableItemComponent {
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
<div class="dialog-actions">
|
||||
<iqser-icon-button
|
||||
(action)="save()"
|
||||
[buttonId]="'save-dossier-state'"
|
||||
[disabled]="disabled"
|
||||
[label]="'add-edit-dossier-state.save' | translate"
|
||||
[submit]="true"
|
||||
|
||||
@ -18,7 +18,6 @@ export interface AddEditDossierStateDialogData {
|
||||
@Component({
|
||||
templateUrl: './add-edit-dossier-state-dialog.component.html',
|
||||
styleUrls: ['./add-edit-dossier-state-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [TranslateModule, ReactiveFormsModule, ColorPickerModule, MatIcon, NgIf, IconButtonComponent, CircleButtonComponent],
|
||||
})
|
||||
export class AddEditDossierStateDialogComponent extends BaseDialogComponent {
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<div [innerHTML]="'confirm-delete-dossier-state.warning' | translate : translateArgs" class="heading"></div>
|
||||
<div [innerHTML]="'confirm-delete-dossier-state.warning' | translate: translateArgs" class="heading"></div>
|
||||
|
||||
<form *ngIf="data.dossierCount !== 0 && data.otherStates.length > 0" [formGroup]="form" class="mt-16">
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="replace">
|
||||
{{ 'confirm-delete-dossier-state.question' | translate : { count: data.dossierCount } }}
|
||||
{{ 'confirm-delete-dossier-state.question' | translate: { count: data.dossierCount } }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
@ -30,7 +30,12 @@
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<iqser-icon-button (action)="save()" [label]="label | translate" [type]="iconButtonTypes.primary"></iqser-icon-button>
|
||||
<iqser-icon-button
|
||||
(action)="save()"
|
||||
[buttonId]="'confirm-delete-dossier-state'"
|
||||
[label]="label | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
></iqser-icon-button>
|
||||
<div [translate]="'confirm-delete-dossier-state.cancel'" class="all-caps-label cancel" mat-dialog-close></div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.se
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatCheckbox } from '@angular/material/checkbox';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||
import { MatOption, MatSelect } from '@angular/material/select';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
|
||||
export interface ConfirmDeleteDossierStateDialogData {
|
||||
@ -23,13 +23,11 @@ export interface ConfirmDeleteDossierStateDialogData {
|
||||
@Component({
|
||||
templateUrl: './confirm-delete-dossier-state-dialog.component.html',
|
||||
styleUrls: ['./confirm-delete-dossier-state-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
TranslateModule,
|
||||
ReactiveFormsModule,
|
||||
MatCheckbox,
|
||||
MatFormField,
|
||||
MatSelectTrigger,
|
||||
MatSelect,
|
||||
MatOption,
|
||||
NgForOf,
|
||||
|
||||
@ -33,7 +33,6 @@ import { DossierStatesTableItemComponent } from '../dossier-states-table-item/do
|
||||
templateUrl: './dossier-states-listing-screen.component.html',
|
||||
styleUrls: ['./dossier-states-listing-screen.component.scss'],
|
||||
providers: listingProvidersFactory(DossierStatesListingScreenComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
DonutChartComponent,
|
||||
|
||||
@ -13,18 +13,20 @@
|
||||
<span class="small-label">{{ state.dossierCount }}</span>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div [id]="'dossier_' + (state.name | snakeCase)" class="cell">
|
||||
<div *ngIf="permissionsService.canPerformDossierStatesActions()" class="action-buttons">
|
||||
<div [attr.help-mode-key]="'edit_delete_dossier_state'">
|
||||
<iqser-circle-button
|
||||
(action)="openEditStateDialog(state)"
|
||||
[tooltip]="'dossier-states-listing.action.edit' | translate"
|
||||
[buttonId]="'dossier-state-edit-button'"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="openConfirmDeleteStateDialog(state)"
|
||||
[tooltip]="'dossier-states-listing.action.delete' | translate"
|
||||
[buttonId]="'dossier-state-delete-button'"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
@ -14,13 +14,13 @@ import {
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { SnakeCasePipe } from '@common-ui/pipes/snake-case.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-states-table-item',
|
||||
templateUrl: './dossier-states-table-item.component.html',
|
||||
styleUrls: ['./dossier-states-table-item.component.scss'],
|
||||
standalone: true,
|
||||
imports: [MatTooltip, CircleButtonComponent, TranslateModule, NgIf],
|
||||
imports: [MatTooltip, CircleButtonComponent, TranslateModule, NgIf, SnakeCasePipe],
|
||||
})
|
||||
export class DossierStatesTableItemComponent {
|
||||
readonly #dialog = inject(MatDialog);
|
||||
|
||||
@ -33,7 +33,6 @@ import { TableItemComponent } from '../table-item/table-item.component';
|
||||
entitiesService: DossierTemplatesService,
|
||||
component: DossierTemplatesListingScreenComponent,
|
||||
}),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
TranslateModule,
|
||||
|
||||
@ -17,7 +17,6 @@ import { DatePipe } from '@shared/pipes/date.pipe';
|
||||
templateUrl: './table-item.component.html',
|
||||
styleUrls: ['./table-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [MatTooltip, NgIf, AsyncPipe, MatIcon, TranslateModule, DatePipe, DossierTemplateActionsComponent, InitialsAvatarComponent],
|
||||
})
|
||||
export class TableItemComponent implements OnChanges {
|
||||
|
||||
@ -87,6 +87,7 @@
|
||||
[routerLink]="dict.routerLink"
|
||||
[tooltip]="'entities-listing.action.edit' | translate"
|
||||
icon="iqser:edit"
|
||||
iqserStopPropagation
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
ListingComponent,
|
||||
listingProvidersFactory,
|
||||
LoadingService,
|
||||
StopPropagationDirective,
|
||||
TableColumnConfig,
|
||||
} from '@iqser/common-ui';
|
||||
import { getParam } from '@iqser/common-ui/lib/utils';
|
||||
@ -29,7 +30,6 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
templateUrl: './entities-listing-screen.component.html',
|
||||
styleUrls: ['./entities-listing-screen.component.scss'],
|
||||
providers: listingProvidersFactory(EntitiesListingScreenComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
TranslateModule,
|
||||
@ -41,6 +41,7 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
AnnotationIconComponent,
|
||||
AsyncPipe,
|
||||
RouterLink,
|
||||
StopPropagationDirective,
|
||||
],
|
||||
})
|
||||
export class EntitiesListingScreenComponent extends ListingComponent<Dictionary> implements OnInit {
|
||||
|
||||
@ -16,7 +16,6 @@ import { AsyncPipe } from '@angular/common';
|
||||
templateUrl: './dictionary-screen.component.html',
|
||||
styleUrls: ['./dictionary-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, DictionaryManagerComponent],
|
||||
})
|
||||
export class DictionaryScreenComponent implements OnInit {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { getConfig, HasScrollbarDirective, HelpButtonComponent, IconButtonComponent, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { getConfig, HasScrollbarDirective, IconButtonComponent, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { IqserEventTarget } from '@iqser/common-ui/lib/utils';
|
||||
import { Dictionary, DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
@ -17,17 +17,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
templateUrl: './entity-info.component.html',
|
||||
styleUrls: ['./entity-info.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
HasScrollbarDirective,
|
||||
MatIcon,
|
||||
NgIf,
|
||||
TranslateModule,
|
||||
AsyncPipe,
|
||||
IconButtonComponent,
|
||||
AddEditEntityComponent,
|
||||
HelpButtonComponent,
|
||||
],
|
||||
imports: [HasScrollbarDirective, MatIcon, NgIf, TranslateModule, AsyncPipe, IconButtonComponent, AddEditEntityComponent],
|
||||
})
|
||||
export class EntityInfoComponent {
|
||||
@ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent;
|
||||
|
||||
@ -22,7 +22,6 @@ export interface AddEditFileAttributeDialogData {
|
||||
@Component({
|
||||
templateUrl: './add-edit-file-attribute-dialog.component.html',
|
||||
styleUrls: ['./add-edit-file-attribute-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
TranslateModule,
|
||||
|
||||
@ -13,7 +13,6 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
@Component({
|
||||
templateUrl: './file-attributes-configurations-dialog.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
MatSlideToggleModule,
|
||||
@ -58,6 +57,7 @@ export class FileAttributesConfigurationsDialogComponent extends BaseDialogCompo
|
||||
if (supportCsvMapping) {
|
||||
return {
|
||||
...this.#configuration,
|
||||
keyColumn: this.form.get('keyColumn').value,
|
||||
filenameMappingColumnHeaderName: this.form.get('keyColumn').value,
|
||||
delimiter: this.form.get('delimiter').value,
|
||||
encoding: this.form.get('encodingType').value,
|
||||
@ -67,13 +67,14 @@ export class FileAttributesConfigurationsDialogComponent extends BaseDialogCompo
|
||||
return {
|
||||
...this.#configuration,
|
||||
filenameMappingColumnHeaderName: '',
|
||||
keyColumn: this.form.get('keyColumn').value,
|
||||
};
|
||||
}
|
||||
|
||||
#getForm() {
|
||||
return this._formBuilder.group({
|
||||
supportCsvMapping: [!!this.#configuration.filenameMappingColumnHeaderName],
|
||||
keyColumn: [this.#configuration.filenameMappingColumnHeaderName || '', [Validators.required]],
|
||||
keyColumn: [this.#configuration.filenameMappingColumnHeaderName || this.#configuration.keyColumn || '', [Validators.required]],
|
||||
delimiter: [this.#configuration.delimiter || '', [Validators.required]],
|
||||
encodingType: [this.#configuration.encoding || FileAttributeEncodingTypes['UTF-8'], [Validators.required]],
|
||||
});
|
||||
|
||||
@ -2,8 +2,8 @@ import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MatMenu, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { MatOption, MatSelect } from '@angular/material/select';
|
||||
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { ChevronButtonComponent } from '@common-ui/buttons/chevron-button';
|
||||
@ -19,7 +19,6 @@ import { fileAttributeTypesTranslations } from '@translations/file-attribute-typ
|
||||
templateUrl: './active-fields-listing.component.html',
|
||||
styleUrls: ['./active-fields-listing.component.scss'],
|
||||
providers: listingProvidersFactory(ActiveFieldsListingComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
CircleButtonComponent,
|
||||
@ -30,7 +29,6 @@ import { fileAttributeTypesTranslations } from '@translations/file-attribute-typ
|
||||
MatMenu,
|
||||
EditableInputComponent,
|
||||
MatFormField,
|
||||
MatSelectTrigger,
|
||||
MatSelect,
|
||||
MatOption,
|
||||
FormsModule,
|
||||
@ -38,6 +36,7 @@ import { fileAttributeTypesTranslations } from '@translations/file-attribute-typ
|
||||
RoundCheckboxComponent,
|
||||
NgForOf,
|
||||
NgIf,
|
||||
MatMenuItem,
|
||||
],
|
||||
})
|
||||
export class ActiveFieldsListingComponent extends ListingComponent<IField> implements OnChanges {
|
||||
|
||||
@ -4,7 +4,7 @@ import { AbstractControl, ReactiveFormsModule, UntypedFormBuilder, UntypedFormGr
|
||||
import { MatAutocomplete, MatAutocompleteTrigger, MatOption } from '@angular/material/autocomplete';
|
||||
import { MAT_DIALOG_DATA, MatDialogClose, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { InputWithActionComponent } from '@common-ui/inputs/input-with-action/input-with-action.component';
|
||||
import {
|
||||
@ -38,7 +38,6 @@ export interface IFileAttributesCSVImportData {
|
||||
styleUrls: ['./file-attributes-csv-import-dialog.component.scss'],
|
||||
providers: listingProvidersFactory(),
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
MatFormField,
|
||||
@ -46,7 +45,6 @@ export interface IFileAttributesCSVImportData {
|
||||
MatAutocomplete,
|
||||
AsyncPipe,
|
||||
MatOption,
|
||||
MatSelectTrigger,
|
||||
MatSelect,
|
||||
CircleButtonComponent,
|
||||
NgIf,
|
||||
|
||||
@ -46,7 +46,6 @@ import {
|
||||
templateUrl: './file-attributes-listing-screen.component.html',
|
||||
styleUrls: ['./file-attributes-listing-screen.component.scss'],
|
||||
providers: listingProvidersFactory(FileAttributesListingScreenComponent),
|
||||
standalone: true,
|
||||
imports: [
|
||||
IqserListingModule,
|
||||
NgForOf,
|
||||
@ -86,6 +85,7 @@ export default class FileAttributesListingScreenComponent extends ListingCompone
|
||||
},
|
||||
];
|
||||
readonly roles = Roles;
|
||||
keyColumnValue: string = '';
|
||||
|
||||
constructor(
|
||||
readonly permissionsService: PermissionsService,
|
||||
@ -172,13 +172,13 @@ export default class FileAttributesListingScreenComponent extends ListingCompone
|
||||
FileAttributesConfigurationsDialogComponent,
|
||||
{
|
||||
...defaultDialogConfig,
|
||||
data: this.#existingConfiguration,
|
||||
data: { ...this.#existingConfiguration, keyColumn: this.keyColumnValue },
|
||||
},
|
||||
);
|
||||
|
||||
const configuration = await firstValueFrom(ref.afterClosed());
|
||||
|
||||
if (configuration) {
|
||||
this.keyColumnValue = configuration.keyColumn;
|
||||
await this.#setConfigAndLoadData(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<div class="dialog-header">
|
||||
<div class="heading-l" translate="general-config-screen.general.title"></div>
|
||||
<div translate="general-config-screen.general.subtitle"></div>
|
||||
</div>
|
||||
<form (submit)="save()" *ngIf="form" [formGroup]="form">
|
||||
<div class="dialog-content">
|
||||
|
||||
@ -13,7 +13,6 @@ import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||
@Component({
|
||||
selector: 'redaction-general-config-form',
|
||||
templateUrl: './general-config-form.component.html',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, TranslateModule, NgIf, MatSlideToggle, IconButtonComponent],
|
||||
})
|
||||
export class GeneralConfigFormComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
@ -11,7 +11,12 @@
|
||||
<div class="dialog mt-24 mb-0">
|
||||
<redaction-system-preferences-form></redaction-system-preferences-form>
|
||||
</div>
|
||||
<div class="dialog mt-24">
|
||||
<redaction-smtp-form></redaction-smtp-form>
|
||||
</div>
|
||||
|
||||
@if (smtpLicenseFeatureEnabled) {
|
||||
<div class="dialog mt-24">
|
||||
<redaction-smtp-form></redaction-smtp-form>
|
||||
</div>
|
||||
} @else {
|
||||
<div style="visibility: hidden" class="dialog mt-24"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -6,26 +6,29 @@ import { BaseFormComponent, IqserListingModule } from '@iqser/common-ui';
|
||||
import { SystemPreferencesFormComponent } from './system-preferences-form/system-preferences-form.component';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { LicenseService } from '@services/license.service';
|
||||
import { ILicenseFeature } from '@red/domain';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-general-config-screen',
|
||||
templateUrl: './general-config-screen.component.html',
|
||||
styleUrls: ['./general-config-screen.component.scss'],
|
||||
standalone: true,
|
||||
imports: [IqserListingModule, GeneralConfigFormComponent, SystemPreferencesFormComponent, SmtpFormComponent, TranslateModule],
|
||||
})
|
||||
export class GeneralConfigScreenComponent extends BaseFormComponent implements AfterViewInit {
|
||||
readonly currentUser = inject(UserService).currentUser;
|
||||
readonly routerHistoryService = inject(RouterHistoryService);
|
||||
readonly licenseService = inject(LicenseService);
|
||||
|
||||
@ViewChild(GeneralConfigFormComponent) generalConfigFormComponent: GeneralConfigFormComponent;
|
||||
@ViewChild(SystemPreferencesFormComponent) systemPreferencesFormComponent: SystemPreferencesFormComponent;
|
||||
@ViewChild(SmtpFormComponent) smtpFormComponent: SmtpFormComponent;
|
||||
children: BaseFormComponent[];
|
||||
smtpLicenseFeatureEnabled: boolean;
|
||||
|
||||
get changed(): boolean {
|
||||
for (const child of this.children) {
|
||||
if (child.changed) {
|
||||
if (child?.changed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -43,6 +46,8 @@ export class GeneralConfigScreenComponent extends BaseFormComponent implements A
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.children = [this.generalConfigFormComponent, this.systemPreferencesFormComponent, this.smtpFormComponent];
|
||||
let licenseFeature: ILicenseFeature = this.licenseService.getFeature('configurableSMTPServer');
|
||||
this.smtpLicenseFeatureEnabled = licenseFeature != null && licenseFeature.value === true;
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
|
||||
@ -21,7 +21,6 @@ import { NgIf } from '@angular/common';
|
||||
@Component({
|
||||
selector: 'redaction-smtp-form',
|
||||
templateUrl: './smtp-form.component.html',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, TranslateModule, MatSlideToggle, IconButtonComponent, NgIf],
|
||||
})
|
||||
export class SmtpFormComponent extends BaseFormComponent implements OnInit {
|
||||
|
||||
@ -15,7 +15,6 @@ export type ValueType = 'number' | 'string' | 'boolean';
|
||||
@Component({
|
||||
selector: 'redaction-system-preferences-form',
|
||||
templateUrl: './system-preferences-form.component.html',
|
||||
standalone: true,
|
||||
imports: [NgIf, ReactiveFormsModule, NgForOf, TranslateModule, MatSlideToggle, IconButtonComponent],
|
||||
})
|
||||
export class SystemPreferencesFormComponent extends BaseFormComponent {
|
||||
|
||||
@ -34,6 +34,20 @@
|
||||
<span [innerHTML]="'dossier-template-info-screen.created-on' | translate: { date: createdOn }"></span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="areRulesLocked()">
|
||||
<mat-icon
|
||||
(click)="resetRules()"
|
||||
[matTooltip]="
|
||||
currentUser.isAdmin
|
||||
? ('dossier-template-info-screen.rules-reset.tooltip' | translate)
|
||||
: ('dossier-template-info-screen.rules-reset.disabled-action' | translate)
|
||||
"
|
||||
[class.action-icon]="currentUser.isAdmin"
|
||||
svgIcon="iqser:alert-circle"
|
||||
></mat-icon>
|
||||
<span class="error">{{ 'dossier-template-info-screen.rules-reset.label' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ 'dossier-template-info-screen.entries' | translate: { count: ctx.stats.numberOfEntries } }}
|
||||
|
||||
@ -18,3 +18,11 @@
|
||||
padding-right: 24px;
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--iqser-primary);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, computed, Input, OnInit } from '@angular/core';
|
||||
import { ContextComponent } from '@iqser/common-ui/lib/utils';
|
||||
import { type DossierTemplate, type DossierTemplateStats } from '@red/domain';
|
||||
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
||||
@ -9,6 +9,12 @@ import { MatIcon } from '@angular/material/icon';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InitialsAvatarComponent } from '@common-ui/users';
|
||||
import { DatePipe } from '@shared/pipes/date.pipe';
|
||||
import { RulesService } from '../../../services/rules.service';
|
||||
import { Toaster } from '@iqser/common-ui';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { getCurrentUser } from '@users/user.service';
|
||||
|
||||
interface Context {
|
||||
readonly dossierTemplate: DossierTemplate;
|
||||
@ -19,17 +25,21 @@ interface Context {
|
||||
selector: 'redaction-dossier-template-details',
|
||||
templateUrl: './dossier-template-details.component.html',
|
||||
styleUrls: ['./dossier-template-details.component.scss'],
|
||||
standalone: true,
|
||||
imports: [NgIf, AsyncPipe, MatIcon, TranslateModule, DatePipe, InitialsAvatarComponent],
|
||||
imports: [NgIf, AsyncPipe, MatIcon, TranslateModule, DatePipe, InitialsAvatarComponent, MatTooltip],
|
||||
})
|
||||
export class DossierTemplateDetailsComponent extends ContextComponent<Context> implements OnInit {
|
||||
readonly translations = dossierTemplateStatusTranslations;
|
||||
|
||||
@Input({ required: true }) dossierTemplateId: string;
|
||||
readonly areRulesLocked = computed(() => {
|
||||
return this._rulesService.currentTemplateRules().timeoutDetected;
|
||||
});
|
||||
readonly currentUser = getCurrentUser();
|
||||
|
||||
constructor(
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
private readonly _rulesService: RulesService,
|
||||
private readonly _toaster: Toaster,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@ -40,4 +50,15 @@ export class DossierTemplateDetailsComponent extends ContextComponent<Context> i
|
||||
stats: this._dossierTemplateStatsService.watch$(this.dossierTemplateId),
|
||||
});
|
||||
}
|
||||
|
||||
async resetRules() {
|
||||
if (!this.currentUser.isAdmin) return;
|
||||
try {
|
||||
await firstValueFrom(this._rulesService.reset(this.dossierTemplateId));
|
||||
this._toaster.success(_('dossier-template-info-screen.rules-reset.success'));
|
||||
await firstValueFrom(this._rulesService.getFor(this.dossierTemplateId));
|
||||
} catch (error) {
|
||||
this._toaster.rawError(error.error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,13 +22,12 @@ import { Observable } from 'rxjs';
|
||||
import { DossierTemplateDetailsComponent } from '../dossier-template-details/dossier-template-details.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatCheckbox } from '@angular/material/checkbox';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { SelectComponent } from '@shared/components/select/select.component';
|
||||
import { MatSuffix } from '@angular/material/form-field';
|
||||
|
||||
const downloadTypes = ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED'].map(type => ({
|
||||
const downloadTypes = ['ORIGINAL', 'PREVIEW', 'OPTIMIZED_PREVIEW', 'DELTA_PREVIEW', 'REDACTED'].map(type => ({
|
||||
key: type,
|
||||
label: downloadTypesTranslations[type],
|
||||
}));
|
||||
@ -36,14 +35,12 @@ const downloadTypes = ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED'].map(t
|
||||
@Component({
|
||||
templateUrl: './dossier-template-info-screen.component.html',
|
||||
styleUrls: ['./dossier-template-info-screen.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
HasScrollbarDirective,
|
||||
ReactiveFormsModule,
|
||||
DossierTemplateDetailsComponent,
|
||||
TranslateModule,
|
||||
MatCheckbox,
|
||||
NgIf,
|
||||
MatDatepickerModule,
|
||||
SelectComponent,
|
||||
IconButtonComponent,
|
||||
|
||||
@ -17,8 +17,17 @@
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="iqser-input-group">
|
||||
<label translate="add-edit-entity.form.technical-name"></label>
|
||||
<div class="technical-name">{{ this.technicalName() || '-' }}</div>
|
||||
<span
|
||||
[translateParams]="{ type: data.justification ? 'edit' : 'create' }"
|
||||
[translate]="'add-edit-entity.form.technical-name-hint'"
|
||||
class="hint"
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required w-400">
|
||||
<div class="iqser-input-group w-400">
|
||||
<label translate="add-edit-justification.form.reason"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-justification.form.reason-placeholder' | translate"
|
||||
@ -28,7 +37,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required w-400">
|
||||
<div class="iqser-input-group w-400">
|
||||
<label translate="add-edit-justification.form.description"></label>
|
||||
<textarea
|
||||
[placeholder]="'add-edit-justification.form.description-placeholder' | translate"
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, computed, Inject, untracked } from '@angular/core';
|
||||
import { ReactiveFormsModule, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Justification } from '@red/domain';
|
||||
import { JustificationsService } from '@services/entity-services/justifications.service';
|
||||
import { BaseDialogComponent, CircleButtonComponent, IconButtonComponent } from '@iqser/common-ui';
|
||||
import { BaseDialogComponent, CircleButtonComponent, HasScrollbarDirective, IconButtonComponent } from '@iqser/common-ui';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { formControlToSignal } from '@utils/functions';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
|
||||
interface DialogData {
|
||||
justification?: Justification;
|
||||
@ -15,10 +17,29 @@ interface DialogData {
|
||||
@Component({
|
||||
templateUrl: './add-edit-justification-dialog.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [TranslateModule, ReactiveFormsModule, IconButtonComponent, CircleButtonComponent],
|
||||
imports: [TranslateModule, ReactiveFormsModule, IconButtonComponent, CircleButtonComponent, HasScrollbarDirective],
|
||||
})
|
||||
export class AddEditJustificationDialogComponent extends BaseDialogComponent {
|
||||
readonly form = this.#getForm();
|
||||
readonly name = formControlToSignal(this.form.controls['name']);
|
||||
readonly allJustifications = toSignal(this._justificationService.all$);
|
||||
readonly technicalName = computed(() => {
|
||||
if (this.data.justification) {
|
||||
return this.data.justification.technicalName;
|
||||
}
|
||||
if (!this.name()) {
|
||||
return null;
|
||||
}
|
||||
let currentTechnicalName = Justification.toTechnicalName(this.name());
|
||||
const existingTechnicalNames = untracked(this.allJustifications).map(justification => justification.technicalName);
|
||||
let suffix = 1;
|
||||
while (existingTechnicalNames.includes(currentTechnicalName)) {
|
||||
currentTechnicalName =
|
||||
currentTechnicalName === '_' ? `${currentTechnicalName}${suffix++}` : [currentTechnicalName, suffix++].join('_');
|
||||
}
|
||||
return currentTechnicalName;
|
||||
});
|
||||
|
||||
constructor(
|
||||
private readonly _justificationService: JustificationsService,
|
||||
protected readonly _dialogRef: MatDialogRef<AddEditJustificationDialogComponent>,
|
||||
@ -26,7 +47,6 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent {
|
||||
) {
|
||||
super(_dialogRef, !!data.justification);
|
||||
|
||||
this.form = this._getForm();
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
@ -34,7 +54,8 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent {
|
||||
const dossierTemplateId = this.data.dossierTemplateId;
|
||||
this._loadingService.start();
|
||||
try {
|
||||
await firstValueFrom(this._justificationService.createOrUpdate(this.form.getRawValue() as Justification, dossierTemplateId));
|
||||
const formValue = { ...this.form.getRawValue(), technicalName: this.technicalName() };
|
||||
await firstValueFrom(this._justificationService.createOrUpdate(formValue as Justification, dossierTemplateId));
|
||||
await firstValueFrom(this._justificationService.loadAll(dossierTemplateId));
|
||||
this._dialogRef.close(true);
|
||||
} catch (error) {
|
||||
@ -43,11 +64,12 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent {
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
private _getForm(): UntypedFormGroup {
|
||||
#getForm(): UntypedFormGroup {
|
||||
return this._formBuilder.group({
|
||||
name: [{ value: this.data.justification?.name, disabled: !!this.data.justification }, Validators.required],
|
||||
reason: [this.data.justification?.reason, Validators.required],
|
||||
description: [this.data.justification?.description, Validators.required],
|
||||
reason: [this.data.justification?.reason],
|
||||
description: [this.data.justification?.description],
|
||||
technicalName: [this.data.justification?.technicalName ?? null],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
}),
|
||||
JustificationsDialogService,
|
||||
],
|
||||
standalone: true,
|
||||
imports: [IqserListingModule, CircleButtonComponent, NgIf, TableItemComponent, TranslateModule, AsyncPipe, IconButtonComponent],
|
||||
})
|
||||
export default class JustificationsScreenComponent extends ListingComponent<Justification> implements OnInit {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user