Compare commits

...

261 Commits

Author SHA1 Message Date
645a84c82a Update changelog v1.0.4 2021-05-28 17:44:37 +00:00
925fc43d0f Bump version (changelog ignore) 2021-05-28 19:41:15 +02:00
8e33d24c63 Instructions for custom themes with custom components 2021-05-28 19:23:38 +02:00
984ef63661 Update changelog v1.0.3 2021-05-23 20:22:50 +00:00
a8daf175ea Instuction about how to integrate with non CRA projects 2021-05-23 22:19:51 +02:00
055263a3da Add mention to awesome list 2021-05-15 22:41:30 +02:00
9990b0ab05 fmt (changelog ignore) 2021-05-01 18:05:40 +02:00
423397ce3e Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-05-01 18:04:07 +02:00
954567712c Give hint about where to find the ftl files (changelog ignore) 2021-05-01 18:03:35 +02:00
9f52eb8123 Update changelog v1.0.2 2021-05-01 14:17:28 +00:00
744b198fb4 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-05-01 16:15:44 +02:00
15eab797c3 Add key for child in a list (changelog ignore) 2021-05-01 16:15:40 +02:00
8ff86b1e29 Update changelog v1.0.1 2021-05-01 14:12:41 +00:00
e1b8760ee3 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-05-01 16:10:57 +02:00
bd0d890b2c Fix: LoginOtp (and not otc) 2021-05-01 16:10:52 +02:00
2a2118d769 Update changelog v1.0.0 2021-05-01 13:52:33 +00:00
9839b64650 Bump version (changelog ignore) 2021-05-01 15:50:45 +02:00
2bf55e12f9 Guide for implementing a missing page (fix, changelog ignore) 2021-05-01 15:50:12 +02:00
2249fa9232 #4: Guide for implementing a missing page 2021-05-01 15:48:49 +02:00
f673a65304 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-05-01 14:56:01 +02:00
0163459ad6 Support OTP #4 2021-05-01 14:55:58 +02:00
b21123cc9d Update changelog v0.4.4 2021-04-29 21:33:33 +00:00
7800d125b2 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-04-29 23:31:12 +02:00
89ea648f18 Fix previous release 2021-04-29 23:31:05 +02:00
ab7ac3c2d0 Update changelog v0.4.3 2021-04-29 17:07:48 +00:00
b16319d962 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-04-29 19:02:16 +02:00
f8012d5dfb Bump version (changelog ignore) 2021-04-29 19:00:56 +02:00
45a2015597 Add infos about the plugin that defines authorizedMailDomains 2021-04-29 19:00:38 +02:00
524ab000be Update changelog v0.4.2 2021-04-29 16:47:44 +00:00
d73cfb8765 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-04-29 18:42:29 +02:00
8164f5373f Client side validation of allowed email domains 2021-04-29 18:42:14 +02:00
824b0c275e fmt (changelog ignore) 2021-04-21 20:45:03 +02:00
f8d83d7a37 Update README (changelog ignore) 2021-04-20 11:44:57 +02:00
b291526b13 Support email whitlisting 2021-04-15 12:20:08 +02:00
e1c310d383 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-04-12 23:46:29 +02:00
242777a8eb Restore kickstart video in the readme 2021-04-12 23:46:24 +02:00
10a6b70fe9 Update README.md 2021-04-12 19:27:54 +02:00
c829f5969c Update README.md 2021-04-12 18:51:16 +02:00
ba6a5047b1 Add note (changelog ignore) 2021-04-12 04:59:39 +02:00
852f48c05f update gif (changelog ignore) 2021-04-12 04:47:53 +02:00
c342f04a92 Update video (changelog ignore) 2021-04-12 04:21:18 +02:00
42eb8147c6 fmt (changelog ignore) 2021-04-12 02:29:24 +02:00
ebcdbd782f fmt (changelog ignore) 2021-04-12 02:28:22 +02:00
d2059e08d1 fmt (changelog ignore) 2021-04-12 02:25:48 +02:00
4f075882d5 Merge branch 'main' of https://github.com/garronej/keycloakify into main 2021-04-12 02:24:17 +02:00
044ec1a2da Important readme update 2021-04-12 02:24:11 +02:00
a49a32703d Update changelog v0.4.1 2021-04-11 16:24:36 +00:00
46ec832767 Quietly re-introduce --external-assets 2021-04-11 18:18:52 +02:00
fc858b3db6 Update screenshot (changelog ignore) 2021-04-11 01:21:01 +02:00
3cd8843157 Update screenshot in readme for therms and conditions (changelog ignore) 2021-04-10 20:20:26 +02:00
c9358ea8dd Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-09 04:02:30 +02:00
354a4db0f6 Give example of customization 2021-04-09 04:02:23 +02:00
90d435d96b Update changelog v0.4.0 2021-04-09 01:31:07 +00:00
2d804f0f0f Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-09 03:26:06 +02:00
1c9acedac0 Bump version (changelog ignore) 2021-04-09 03:26:01 +02:00
6e914e4ea3 Acual support of Therms of services 2021-04-09 03:25:39 +02:00
f0c4786267 Update changelog v0.3.24 2021-04-08 16:14:10 +00:00
0b16159312 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-08 18:00:04 +02:00
ea8a91e069 Add missing dependency: markdown 2021-04-08 17:59:58 +02:00
59db202fe4 Update changelog v0.3.23 2021-04-08 15:43:34 +00:00
09927afd43 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-08 17:40:54 +02:00
13c6122b9b Bump version (changelog ignore) 2021-04-08 17:06:26 +02:00
1bb19f65a2 Allow to lazily load therms 2021-04-08 17:06:09 +02:00
918a80cfb6 Update changelog v0.3.22 2021-04-08 13:48:41 +00:00
ed7d5eabcb Bump version (changelog ignore) 2021-04-08 15:43:12 +02:00
2795109162 update powerhooks 2021-04-08 15:42:41 +02:00
966f277628 Support terms and condition 2021-04-08 15:41:40 +02:00
36d60411f9 Fix info.ftl 2021-04-08 12:54:29 +02:00
60fe33f3fd Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-08 12:20:14 +02:00
1df685df92 For useKcMessage we prefer returning callbacks with a changing references 2021-04-08 12:20:06 +02:00
7894d95ace Update changelog v0.3.21 2021-04-04 19:20:27 +00:00
a8b4493aa1 update yarn.lock (changelog ignore) 2021-04-04 21:17:35 +02:00
715a7399cf Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-04 21:12:39 +02:00
a1e59bae23 Update powerhooks 2021-04-04 21:12:30 +02:00
b0819314a1 Update changelog v0.3.20 2021-04-01 22:37:41 +00:00
0099442543 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-01 23:43:14 +02:00
66a0b07228 Bump version (changelog ignore) 2021-04-01 23:43:08 +02:00
85f9544754 Always catch freemarker errors 2021-04-01 23:42:31 +02:00
2f16a09ab8 Update changelog v0.3.19 2021-04-01 15:21:10 +00:00
183ae98c30 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-01 17:16:01 +02:00
ba15e63879 Bump version (changelog ignore) 2021-04-01 17:15:55 +02:00
654277feda Fix previous release 2021-04-01 17:15:28 +02:00
81279a5cc5 Update changelog v0.3.18 2021-04-01 15:04:08 +00:00
59f0a843b0 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-01 16:52:53 +02:00
c094f70171 Bump version (changelog ignore) 2021-04-01 16:51:50 +02:00
0858fe6319 Fix error.ftt, Adopt best effort strategy to convert ftl values into JS 2021-04-01 16:51:28 +02:00
5012ec0ccc Update changelog v0.3.17 2021-03-29 04:33:07 +00:00
990a24fab2 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-29 06:27:19 +02:00
036b6bf82a Use push instead of replace in keycloak-js adapter to enable going back 2021-03-29 06:27:12 +02:00
8272a02b52 Update changelog v0.3.15 2021-03-28 12:18:37 +00:00
e346b1d9d2 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-28 14:14:52 +02:00
2309bd21c6 Remove all reference to --external-assets, broken feature 2021-03-28 14:14:43 +02:00
7d6476c1b5 Update changelog v0.3.14 2021-03-28 11:39:36 +00:00
e892a0e7e6 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-28 13:37:07 +02:00
ca5b41e730 Fix standalone mode: imports from js 2021-03-28 13:37:02 +02:00
9b18234112 Update changelog v0.3.13 2021-03-26 16:54:38 +00:00
5274368f47 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 17:49:36 +01:00
1415c24028 Bump version (changelog ignore) 2021-03-26 17:49:31 +01:00
4a084f5859 Fix previous release (changelog ignore) 2021-03-26 17:49:09 +01:00
a30c9eb0cd Update changelog v0.3.12 2021-03-26 16:35:41 +00:00
85d3b40b8e Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 17:31:06 +01:00
335afec230 Bump version (changelog ignore) 2021-03-26 17:31:01 +01:00
69fa49848a Fix mocksContext 2021-03-26 17:30:04 +01:00
7a09051127 Update changelog v0.3.11 2021-03-26 14:36:48 +00:00
07ee0ecb8b Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 15:29:23 +01:00
6f133428f8 Fix previous build, improve README 2021-03-26 15:29:17 +01:00
4f733736db fmt (changelog ignore) 2021-03-26 14:06:14 +01:00
d96ff13a67 Update changelog v0.3.10 2021-03-26 13:05:25 +00:00
2c1351ce47 fmt (changelog ignore) 2021-03-26 14:04:45 +01:00
96cd56ec77 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-26 14:02:46 +01:00
e5b2096d65 Bump version (changelog ignore) 2021-03-26 14:02:40 +01:00
3aa140335f Handle <style> tag, improve documentation 2021-03-26 14:02:14 +01:00
4cafaa2492 Update changelog v0.3.9 2021-03-25 11:54:13 +00:00
9c633a7521 Update readme 2021-03-25 12:48:40 +01:00
e27845ba91 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-25 12:01:15 +01:00
2a8708a45b Document --external-assets 2021-03-25 12:01:11 +01:00
6874fa4c24 Update README.md 2021-03-24 09:12:50 +01:00
ba531a4927 Update README.md 2021-03-24 09:12:04 +01:00
20175b57cf Update README.md 2021-03-24 09:10:44 +01:00
ad275e4c34 Update changelog v0.3.8 2021-03-22 22:36:17 +00:00
060b9fe0de Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 23:34:13 +01:00
17b24d14ed Make standalone mode the default 2021-03-22 23:34:07 +01:00
2d278b0680 Update changelog v0.3.7 2021-03-22 19:57:34 +00:00
fb5975e4f1 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 20:54:35 +01:00
24fccaf513 (test) external asset mode by default 2021-03-22 20:54:28 +01:00
293953aa1b Update changelog v0.3.6 2021-03-22 19:02:53 +00:00
1049e312f9 Fix previous release 2021-03-22 20:00:58 +01:00
a2db250600 Update changelog v0.3.5 2021-03-22 18:43:18 +00:00
cf7fe8c337 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 19:41:08 +01:00
f5350097bf Bump version (changelog ignore) 2021-03-22 19:40:58 +01:00
1cb5dd461b support homepage with urlPath 2021-03-22 19:40:38 +01:00
845599a5e8 Update changelog v0.3.4 2021-03-22 06:23:40 +00:00
0cc02c292f Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 07:21:36 +01:00
1919702326 Bugfix: Import assets from CSS 2021-03-22 07:21:31 +01:00
0c0052e1cd Update changelog v0.3.3 2021-03-22 04:27:01 +00:00
78622770ec Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-22 05:21:22 +01:00
7b86727394 Fix submit not receving correct text 2021-03-22 05:21:05 +01:00
0965f8648e Update changelog v0.3.2 2021-03-21 21:31:01 +00:00
98974b4367 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-21 22:25:49 +01:00
597bcadd9e Fix broken previous release 2021-03-21 22:25:47 +01:00
4d9aabcb91 Update changelog v0.3.1 2021-03-21 21:13:36 +00:00
1606c2884d kcHeaderClass can be updated after initial mount 2021-03-21 22:10:33 +01:00
12f69b593f Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-20 05:07:26 +01:00
1ca45f90d0 Update readme (changelog ignore) 2021-03-20 05:07:22 +01:00
a91a5616f9 Update changelog v0.3.0 2021-03-20 04:02:59 +00:00
c525e09368 Bump version 2021-03-20 05:00:14 +01:00
f5bba4a6a0 Feat: Cary over states using URL search params 2021-03-20 04:59:18 +01:00
77a37fb573 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-20 02:54:21 +01:00
6b24c5878c Bugfix: with kcHtmlClass 2021-03-20 02:54:15 +01:00
f4414e1249 Update changelog v0.2.10 2021-03-19 23:19:03 +00:00
b72971f4ce Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-20 00:17:06 +01:00
b9af4e6804 Bump version (changelog ingnore) 2021-03-20 00:16:58 +01:00
2fd1d42d1e Remove dependency to denoify 2021-03-20 00:16:34 +01:00
3cfc7d7fa9 Update changelog v0.2.9 2021-03-19 23:14:27 +00:00
b5d9055fcf Bump version (changelog ignore) 2021-03-20 00:09:37 +01:00
63d644d95f Update deps and CI workflow 2021-03-20 00:09:12 +01:00
e16192b416 Update changelog v0.2.8 2021-03-19 21:42:31 +00:00
505e018448 Bump version (changelog ignore) 2021-03-19 22:39:48 +01:00
5ced0e2809 Bugfix: keycloak_build that grow and grow in size 2021-03-19 22:39:32 +01:00
0e1d919f7e Add disclaimer about maitainment strategy 2021-03-15 16:22:13 +01:00
a009db998e Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-15 16:05:28 +01:00
d6c6bd933b Add a note for tested version support 2021-03-15 16:05:21 +01:00
859cc03f35 Update changelog v0.2.7 2021-03-13 11:56:59 +00:00
1a3b8ae3b8 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-13 12:51:41 +01:00
863a08abf3 Bump version 2021-03-13 12:51:34 +01:00
fd9c6afa5e Update README.md 2021-03-11 00:10:34 +01:00
8f3797407b Update README.md 2021-03-10 23:55:37 +01:00
7eedb23285 Update changelog v0.2.6 2021-03-10 22:04:25 +00:00
e4a2c95dd8 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-10 23:02:30 +01:00
9429228b71 Bump version (changelog ignore) 2021-03-10 23:02:25 +01:00
aafbc60f12 Fix generated gitignore 2021-03-10 23:02:03 +01:00
7170611791 Update changelog v0.2.5 2021-03-10 21:51:07 +00:00
59e57f3dd5 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-10 22:46:06 +01:00
fd0d25b081 Bump version (changelog ignore) 2021-03-10 22:46:01 +01:00
fa529c911a Fix generated .gitignore 2021-03-10 22:45:09 +01:00
dc997b7ef4 Update changelog v0.2.4 2021-03-10 20:33:36 +00:00
0168d32f96 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-10 21:27:48 +01:00
d6fc0c779c Bump version (changelog ignore) 2021-03-10 21:27:43 +01:00
08be36edfa Update deps (changelog ignore) 2021-03-10 21:27:23 +01:00
990d287953 Update README.md 2021-03-09 05:12:45 +01:00
a629d4ab45 Update readme 2021-03-09 04:56:45 +01:00
78b48af886 Update changelog v0.2.3 2021-03-09 02:07:07 +00:00
72d267853c fix gitignore generation 2021-03-09 03:04:59 +01:00
66a218c2ec Update changelog v0.2.2 2021-03-08 02:02:53 +00:00
d4f3ec2245 Add table of content 2021-03-08 02:59:22 +01:00
7bdc19bf4b Update README.md 2021-03-08 02:55:41 +01:00
103ef788fb Update README.md 2021-03-08 02:54:43 +01:00
b6f6d1f3cc Update README.md 2021-03-08 02:52:58 +01:00
ef3d2e4e04 Update publish.yaml 2021-03-08 02:51:50 +01:00
8ec8b91ead Update changelog v0.2.1 2021-03-08 01:49:47 +00:00
819a1d473d Update ci.yaml 2021-03-08 02:48:02 +01:00
c930337255 Update readme 2021-03-08 02:40:25 +01:00
57bb4a9d96 Bump version (changelog ignore) 2021-03-08 02:36:21 +01:00
1776341242 Update readme 2021-03-08 02:35:58 +01:00
983eec6941 Bump version (changelog ignore) 2021-03-08 02:34:31 +01:00
86d390ee1a update deps 2021-03-08 02:33:52 +01:00
91703409d9 Update readme 2021-03-08 02:29:54 +01:00
3322d0e4a5 Add all mocks for testing 2021-03-08 01:02:06 +01:00
d09038fde2 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-08 00:10:57 +01:00
71966deaac Bump version (changelog ignore) 2021-03-08 00:10:51 +01:00
12e83c9468 many small fixes 2021-03-08 00:09:52 +01:00
fe27357dbb Update changelog v0.1.6 2021-03-07 16:09:08 +00:00
b93003e76d Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-07 17:07:20 +01:00
d6c0e9f783 Bump version (changelog ignore) 2021-03-07 17:05:28 +01:00
18a1baae59 Fix Turkish 2021-03-07 17:05:10 +01:00
2330788995 Update changelog v0.1.5 2021-03-07 15:43:11 +00:00
40c146022a Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-07 16:41:32 +01:00
9844e7554f Bump version changelog ignore 2021-03-07 16:41:27 +01:00
b064b8cbe6 Fix getKcLanguageLabel 2021-03-07 16:41:07 +01:00
997941fbf7 Update changelog v0.1.4 2021-03-07 14:46:12 +00:00
8d5e080bd6 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-07 15:44:38 +01:00
1c1ca25287 Bump version (changelog ignore) 2021-03-07 15:44:33 +01:00
5195b3bc1e Update changelog v0.1.3 2021-03-07 14:39:29 +00:00
3ff56cfea7 Bump version (changelog ignore) 2021-03-07 15:37:58 +01:00
adc6d69201 Implement LoginVerifyEmail 2021-03-07 15:37:37 +01:00
438ca4595f Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-07 14:57:59 +01:00
740d9b7af5 Implement login-reset-password.ftl 2021-03-07 14:57:53 +01:00
919a6947bc Update changelog v0.1.2 2021-03-07 01:17:32 +00:00
85fdaa2f22 Bump version (changelog version) 2021-03-07 02:15:51 +01:00
6ade3d6375 Fix build 2021-03-07 02:15:21 +01:00
73e9ebbe40 Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-07 01:47:10 +01:00
ad78221025 Fix build 2021-03-07 01:47:03 +01:00
714fec0bf3 Update changelog v0.1.1 2021-03-06 22:06:48 +00:00
de312c60b1 Bump version (changelog ignore) 2021-03-06 23:05:15 +01:00
1d07fd7675 Implement Error page 2021-03-06 23:03:03 +01:00
307650aaea rename pageBasename by pageId 2021-03-06 22:41:36 +01:00
6eccd313b6 Implement reactive programing for language switching 2021-03-06 15:16:21 +01:00
b8751d67db Merge branch 'develop' of https://github.com/garronej/keycloakify into develop 2021-03-06 14:43:03 +01:00
25d9d3dc26 Add Info page, refactor 2021-03-06 14:42:56 +01:00
68e6c9faaf Update changelog v0.1.0 2021-03-05 19:44:56 +00:00
f3fb360ce0 Rename keycloakify 2021-03-05 20:43:22 +01:00
d3631dd10c Update changelog v0.0.33 2021-03-05 18:52:19 +00:00
891c91aa20 bump version (changelog ignore) 2021-03-05 19:50:40 +01:00
880018e926 Merge branch 'develop' of https://github.com/garronej/keycloak-react-theming into develop 2021-03-05 19:50:14 +01:00
06ab2ab82e Fix syncronization with non react pages 2021-03-05 19:50:08 +01:00
aafcfb62f2 Update changelog v0.0.32 2021-03-05 14:48:38 +00:00
a69bee8726 bump version 2021-03-05 15:46:55 +01:00
240208793d Add log to tell when we are using react 2021-03-05 15:46:34 +01:00
e7a320f8f8 Merge branch 'develop' of https://github.com/garronej/keycloak-react-theming into develop 2021-03-05 15:44:42 +01:00
f76438dd82 Fix missing parentesis 2021-03-05 15:44:35 +01:00
d6dbb42dea Update changelog v0.0.31 2021-03-05 14:34:34 +00:00
2e076aa058 bump version (changelog ignore) 2021-03-05 15:32:50 +01:00
b59447b840 Fix typo 2021-03-05 15:13:50 +01:00
702352bea2 Merge branch 'develop' of https://github.com/garronej/keycloak-react-theming into develop 2021-03-05 15:08:56 +01:00
98f647fadf Fix register page 500 2021-03-05 14:50:46 +01:00
85d3a011d8 Update changelog v0.0.30 2021-03-05 00:40:09 +00:00
26b0b55a7d Merge branch 'develop' of https://github.com/garronej/keycloak-react-theming into develop 2021-03-05 01:38:37 +01:00
50d0e74c03 Edit language statistique 2021-03-05 01:38:15 +01:00
5a7fb7c303 Update changelog v0.0.30 2021-03-05 00:38:08 +00:00
e9f5a79d69 bump version (changelog ignore) 2021-03-05 01:36:17 +01:00
1378dbebee avoid escaping urls 2021-03-05 01:35:50 +01:00
7daa818996 Use default value instead of value 2021-03-05 00:44:27 +01:00
c8e219361b Fix double single quote problem in messages 2021-03-05 00:23:50 +01:00
b74323a48e Fix typo 2021-03-05 00:14:06 +01:00
0cfe240590 Fix non editable username 2021-03-05 00:03:21 +01:00
533105d63a Fix some bugs 2021-03-04 23:24:43 +01:00
62e4af2c78 Fix Object.deepAssign 2021-03-04 21:50:18 +01:00
934c07f365 Make the dongle to download smaller 2021-03-04 21:43:36 +01:00
624409434a Split kcContext among pages 2021-03-04 21:14:54 +01:00
546c74aa28 Merge branch 'develop' of https://github.com/garronej/keycloak-react-theming into develop 2021-03-04 18:15:59 +01:00
2ee12abc43 Implement register 2021-03-04 18:15:48 +01:00
57 changed files with 4209 additions and 1620 deletions

4
.gitattributes vendored
View File

@ -1,3 +1,3 @@
src/lib/i18n/generated_messages/* linguist-documentation
src/bin/build-keycloak-theme/index.ts -linguist-detectable
src/bin/download-sample-keycloak-themes.ts -linguist-detectable
src/bin/install-builtin-keycloak-themes.ts -linguist-detectable
src/bin/build-keycloak-theme/index.ts -linguist-detectable

View File

@ -2,87 +2,135 @@ name: ci
on:
push:
branches:
- develop
- main
pull_request:
branches:
- develop
- main
jobs:
test_node:
runs-on: ubuntu-latest
test:
runs-on: macos-10.15
strategy:
matrix:
node: [ '14', '13', '12' ]
name: Test with Node v${{ matrix.node }}
steps:
- name: Tell if project is using npm or yarn
id: _1
uses: garronej/github_actions_toolkit@v1.11
id: step1
uses: garronej/github_actions_toolkit@v2.2
with:
action_name: tell_if_project_uses_npm_or_yarn
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
branch: ${{github.ref}}
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/checkout@v2.3.4
- uses: actions/setup-node@v2.1.3
with:
node-version: ${{ matrix.node }}
- if: steps._1.outputs.npm_or_yarn == 'yarn'
- if: steps.step1.outputs.npm_or_yarn == 'yarn'
run: |
yarn install --frozen-lockfile
yarn run build
yarn run test
- if: steps._1.outputs.npm_or_yarn == 'npm'
yarn build
yarn test
- if: steps.step1.outputs.npm_or_yarn == 'npm'
run: |
npm ci
npm run build
npm run test
trigger_publish:
name: Trigger publish.yaml workflow if package.json version updated ( and secrets.PAT is set ).
npm test
check_if_version_upgraded:
name: Check if version upgrade
if: github.event_name == 'push'
runs-on: ubuntu-latest
env:
PAT: ${{secrets.PAT}}
if: github.event_name == 'push' && github.event.head_commit.author.name != 'ts_ci'
needs: test_node
needs: test
outputs:
from_version: ${{ steps.step1.outputs.from_version }}
to_version: ${{ steps.step1.outputs.to_version }}
is_upgraded_version: ${{steps.step1.outputs.is_upgraded_version }}
steps:
- name: Get version on latest
id: v_latest
uses: garronej/github_actions_toolkit@v1.11
- uses: garronej/github_actions_toolkit@v2.2
id: step1
with:
action_name: get_package_json_version
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
branch: latest
compare_to_version: '0.0.0'
action_name: is_package_json_version_upgraded
- name: Get version on develop
id: v_develop
uses: garronej/github_actions_toolkit@v1.11
with:
action_name: get_package_json_version
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
branch: ${{ github.sha }}
compare_to_version: ${{steps.v_latest.outputs.version || '0.0.0'}}
- name: 'Trigger the ''publish'' workflow'
if: ${{ !!env.PAT && steps.v_develop.outputs.compare_result == '1' }}
uses: garronej/github_actions_toolkit@v1.11
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
update_changelog:
runs-on: ubuntu-latest
needs: check_if_version_upgraded
if: needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true'
steps:
- uses: garronej/github_actions_toolkit@v2.2
with:
action_name: dispatch_event
owner: ${{github.repository_owner}}
repo: ${{github.event.repository.name}}
event_type: publish
client_payload_json: |
${{
format(
'{{"from_version":"{0}","to_version":"{1}","repo":"{2}"}}',
steps.v_latest.outputs.version,
steps.v_develop.outputs.version,
github.event.repository.name
)
}}
action_name: update_changelog
branch: ${{ github.ref }}
commit_author_email: ts_ci@github.com
create_github_release:
runs-on: ubuntu-latest
needs:
- update_changelog
- check_if_version_upgraded
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.ref }}
- name: Build GitHub release body
id: step1
run: |
if [ "$FROM_VERSION" = "0.0.0" ]; then
echo "::set-output name=body::🚀"
else
echo "::set-output name=body::📋 [CHANGELOG](https://github.com/$GITHUB_REPOSITORY/blob/v$TO_VERSION/CHANGELOG.md)"
fi
env:
FROM_VERSION: ${{ needs.check_if_version_upgraded.outputs.from_version }}
TO_VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}
- uses: garronej/action-gh-release@v0.2.0
with:
name: Release v${{ needs.check_if_version_upgraded.outputs.to_version }}
tag_name: v${{ needs.check_if_version_upgraded.outputs.to_version }}
target_commitish: ${{ github.ref }}
body: ${{ steps.step1.outputs.body }}
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish_on_npm:
runs-on: macos-10.15
needs:
- update_changelog
- check_if_version_upgraded
steps:
- uses: actions/checkout@v2.3.4
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v2.1.3
with:
node-version: '15'
- run: |
PACKAGE_MANAGER=npm
if [ -f "./yarn.lock" ]; then
PACKAGE_MANAGER=yarn
fi
if [ "$PACKAGE_MANAGER" = "yarn" ]; then
yarn install --frozen-lockfile
else
npm ci
fi
$PACKAGE_MANAGER run build
- run: npx -y -p denoify@0.6.5 denoify_enable_short_npm_import_path
env:
DRY_RUN: "0"
- name: Publishing on NPM
run: |
if [ "$(npm show . version)" = "$VERSION" ]; then
echo "This version is already published"
exit 0
fi
if [ "$NPM_TOKEN" = "" ]; then
echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets"
false
fi
echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
npm publish
rm .npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}

View File

@ -1,116 +0,0 @@
on:
repository_dispatch:
types: publish
jobs:
update_changelog_and_sync_package_lock_version:
name: Update CHANGELOG.md and make sure package.json and package-lock.json versions matches.
runs-on: ubuntu-latest
steps:
- name: Synchronize package.json and package-lock.json version if needed.
uses: garronej/github_actions_toolkit@v1.11
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
action_name: sync_package_and_package_lock_version
owner: ${{github.repository_owner}}
repo: ${{github.event.client_payload.repo}}
branch: develop
commit_author_email: ts_ci@github.com
- name: Update CHANGELOG.md
if: ${{ !!github.event.client_payload.from_version }}
uses: garronej/github_actions_toolkit@v1.11
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
action_name: update_changelog
owner: ${{github.repository_owner}}
repo: ${{github.event.client_payload.repo}}
branch_behind: latest
branch_ahead: develop
commit_author_email: ts_ci@github.com
exclude_commit_from_author_names_json: '["ts_ci"]'
publish:
runs-on: ubuntu-latest
needs: update_changelog_and_sync_package_lock_version
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
ref: develop
- name: Remove .github directory, useless on 'latest' branch
run: rm -r .github
- name: Remove branch 'latest'
continue-on-error: true
run: |
git branch -d latest || true
git push origin :latest
- name: Create the new 'latest' branch
run: |
git branch latest
git checkout latest
- uses: actions/setup-node@v1
- run: |
if [ -f "./yarn.lock" ]; then
yarn install --frozen-lockfile
else
npm ci
fi
- run: |
PACKAGE_MANAGER=npm
if [ -f "./yarn.lock" ]; then
PACKAGE_MANAGER=yarn
fi
$PACKAGE_MANAGER run enable_short_import_path
env:
DRY_RUN: "0"
- name: (DEBUG) Show how the files have been moved to enable short import
run: ls -lR
- name: Publishing on NPM
run: |
if [ "$(npm show . version)" = "$VERSION" ]; then
echo "This version is already published"
exit 0
fi
if [ "$NPM_TOKEN" = "" ]; then
echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets"
false
fi
echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
npm publish
rm .npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
VERSION: ${{ github.event.client_payload.to_version }}
- name: Commit changes
run: |
git config --local user.email "ts_ci@github.com"
git config --local user.name "ts_ci"
git add -A
git commit -am "Enabling shorter import paths [automatic]"
- run: git push origin latest
- name: Release body
id: id_rb
run: |
if [ "$FROM_VERSION" = "" ]; then
echo "::set-output name=body::🚀"
else
echo "::set-output name=body::📋 [CHANGELOG](https://github.com/$OWNER/$REPO/blob/$REF/CHANGELOG.md)"
fi
env:
FROM_VERSION: ${{ github.event.client_payload.from_version }}
OWNER: ${{github.repository_owner}}
REPO: ${{github.event.client_payload.repo}}
REF: v${{github.event.client_payload.to_version}}
- name: Create Release
uses: garronej/create-release@master
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
with:
tag_name: v${{ github.event.client_payload.to_version }}
release_name: Release v${{ github.event.client_payload.to_version }}
branch: latest
draft: false
prerelease: false
body: ${{ steps.id_rb.outputs.body }}

View File

@ -1,3 +1,273 @@
### **1.0.4** (2021-05-28)
- Instructions for custom themes with custom components
### **1.0.3** (2021-05-23)
- Instuction about how to integrate with non CRA projects
- Add mention to awesome list
### **1.0.2** (2021-05-01)
### **1.0.1** (2021-05-01)
- Fix: LoginOtp (and not otc)
# **1.0.0** (2021-05-01)
- #4: Guide for implementing a missing page
- Support OTP #4
### **0.4.4** (2021-04-29)
- Fix previous release
### **0.4.3** (2021-04-29)
- Add infos about the plugin that defines authorizedMailDomains
### **0.4.2** (2021-04-29)
- Client side validation of allowed email domains
- Support email whitlisting
- Restore kickstart video in the readme
- Update README.md
- Update README.md
- Important readme update
### **0.4.1** (2021-04-11)
- Quietly re-introduce --external-assets
- Give example of customization
## **0.4.0** (2021-04-09)
- Acual support of Therms of services
### **0.3.24** (2021-04-08)
- Add missing dependency: markdown
### **0.3.23** (2021-04-08)
- Allow to lazily load therms
### **0.3.22** (2021-04-08)
- update powerhooks
- Support terms and condition
- Fix info.ftl
- For useKcMessage we prefer returning callbacks with a changing references
### **0.3.21** (2021-04-04)
- Update powerhooks
### **0.3.20** (2021-04-01)
- Always catch freemarker errors
### **0.3.19** (2021-04-01)
- Fix previous release
### **0.3.18** (2021-04-01)
- Fix error.ftt, Adopt best effort strategy to convert ftl values into JS
### **0.3.17** (2021-03-29)
- Use push instead of replace in keycloak-js adapter to enable going back
### **0.3.15** (2021-03-28)
- Remove all reference to --external-assets, broken feature
### **0.3.14** (2021-03-28)
- Fix standalone mode: imports from js
### **0.3.13** (2021-03-26)
### **0.3.12** (2021-03-26)
- Fix mocksContext
### **0.3.11** (2021-03-26)
- Fix previous build, improve README
### **0.3.10** (2021-03-26)
- Handle <style> tag, improve documentation
### **0.3.9** (2021-03-25)
- Update readme
- Document --external-assets
- Update README.md
- Update README.md
- Update README.md
### **0.3.8** (2021-03-22)
- Make standalone mode the default
### **0.3.7** (2021-03-22)
- (test) external asset mode by default
### **0.3.6** (2021-03-22)
- Fix previous release
### **0.3.5** (2021-03-22)
- support homepage with urlPath
### **0.3.4** (2021-03-22)
- Bugfix: Import assets from CSS
### **0.3.3** (2021-03-22)
- Fix submit not receving correct text
### **0.3.2** (2021-03-21)
- Fix broken previous release
### **0.3.1** (2021-03-21)
- kcHeaderClass can be updated after initial mount
## **0.3.0** (2021-03-20)
- Bump version
- Feat: Cary over states using URL search params
- Bugfix: with kcHtmlClass
### **0.2.10** (2021-03-19)
- Remove dependency to denoify
### **0.2.9** (2021-03-19)
- Update deps and CI workflow
### **0.2.8** (2021-03-19)
- Bugfix: keycloak_build that grow and grow in size
- Add disclaimer about maitainment strategy
- Add a note for tested version support
### **0.2.7** (2021-03-13)
- Bump version
- Update README.md
- Update README.md
### **0.2.6** (2021-03-10)
- Fix generated gitignore
### **0.2.5** (2021-03-10)
- Fix generated .gitignore
### **0.2.4** (2021-03-10)
- Update README.md
### **0.2.3** (2021-03-09)
- fix gitignore generation
### **0.2.2** (2021-03-08)
- Add table of content
- Update README.md
- Update README.md
## **0.2.1** (2021-03-08)
- Update ci.yaml
- Update readme
- Update readme
- update deps
- Update readme
- Add all mocks for testing
- many small fixes
### **0.1.6** (2021-03-07)
- Fix Turkish
### **0.1.5** (2021-03-07)
- Fix getKcLanguageLabel
### **0.1.4** (2021-03-07)
### **0.1.3** (2021-03-07)
- Implement LoginVerifyEmail
- Implement login-reset-password.ftl
### **0.1.2** (2021-03-07)
- Fix build
- Fix build
### **0.1.1** (2021-03-06)
- Implement Error page
- rename pageBasename by pageId
- Implement reactive programing for language switching
- Add Info page, refactor
## **0.1.0** (2021-03-05)
- Rename keycloakify
### **0.0.33** (2021-03-05)
- Fix syncronization with non react pages
### **0.0.32** (2021-03-05)
- bump version
- Add log to tell when we are using react
- Fix missing parentesis
### **0.0.31** (2021-03-05)
- Fix typo
- Fix register page 500
### **0.0.30** (2021-03-05)
- Edit language statistique
### **0.0.30** (2021-03-05)
- avoid escaping urls
- Use default value instead of value
- Fix double single quote problem in messages
- Fix typo
- Fix non editable username
- Fix some bugs
- Fix Object.deepAssign
- Make the dongle to download smaller
- Split kcContext among pages
- Implement register
### **0.0.29** (2021-03-04)
- Fix build

434
README.md
View File

@ -2,98 +2,388 @@
<img src="https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png">
</p>
<p align="center">
<i>🔏 Keycloak theme generator for Reacts app 🔏</i>
<i>🔏 Create Keycloak themes using React 🔏</i>
<br>
<br>
<img src="https://github.com/garronej/keycloak-react-theming/workflows/ci/badge.svg?branch=develop">
<img src="https://img.shields.io/bundlephobia/minzip/keycloak-react-theming">
<img src="https://img.shields.io/npm/dw/keycloak-react-theming">
<img src="https://img.shields.io/npm/l/keycloak-react-theming">
<img src="https://github.com/garronej/keycloakify/workflows/ci/badge.svg?branch=develop">
<img src="https://img.shields.io/bundlephobia/minzip/keycloakify">
<img src="https://img.shields.io/npm/dw/keycloakify">
<img src="https://img.shields.io/npm/l/keycloakify">
<a href="https://github.com/thomasdarimont/awesome-keycloak">
<img src="https://awesome.re/mentioned-badge.svg"/>
</a>
</p>
**!!! This module is under active developement. It is not usable yet!!!**
<p align="center">
<i>Ultimately this build tool generates a Keycloak theme</i>
<img src="https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png">
</p>
# Motivations
The problem:
Keycloak provides [theme support](https://www.keycloak.org/docs/latest/server_development/#_themes) for web pages. This allows customizing the look and feel of end-user facing pages so they can be integrated with your applications.
It involves, however, a lot of raw JS/CSS/[FTL]() hacking, and bundling the theme is not exactly straightforward.
![keycloak_before](https://user-images.githubusercontent.com/6702424/108838381-dbbbcf80-75d3-11eb-8ae8-db41563ef9db.gif)
Beyond that, if you use Keycloak for a specific app you want your login page to be tightly integrated with it.
Ideally, you don't want the user to notice when he is being redirected away.
When we redirected to Keycloak the user suffers from a harsh context switch.
On je login/register pages the language is set back to default and the theme is different that the one on the app.
Trying to reproduce the look and feel of a specific app in another stack is not an easy task not to mention
the cheer amount of maintenance that it involves.
Keycloak does offer a way to customize theses pages but it requires a lot of raw HTML/CSS hacking
to reproduce the look and feel of a specific app. Not mentioning the maintenance cost of such an endeavour.
<p align="center">
<i>Without keycloakify, users suffers from a harsh context switch, no fronted form pre-validation</i><br>
<img src="https://user-images.githubusercontent.com/6702424/108838381-dbbbcf80-75d3-11eb-8ae8-db41563ef9db.gif">
</p>
Wouldn't it be great if we could just design the login and register pages as if they where part of our app while
still letting Keycloak handle the heavy lifting of actually authenticating the users?
Wouldn't it be great if we could just design the login and register pages as if they were part of our app?
Here is `keycloakify` for you 🍸
Here is `yarn add keycloak-react-theming` for you 🍸
<p align="center">
<i> <a href="https://datalab.sspcloud.fr">With keycloakify:</a> </i>
<br>
<img src="https://user-images.githubusercontent.com/6702424/114332075-c5e37900-9b45-11eb-910b-48a05b3d90d9.gif">
</p>
TODO: Insert video after.
**TL;DR**: [Here](https://github.com/garronej/keycloakify-demo-app) is a Hello World React project with Keycloakify set up.
*NOTE: No autocomplete here just because it was an incognito window.*
If you already have a Keycloak custom theme, it can be easily ported to Keycloakify.
---
- [Motivations](#motivations)
- [Requirements](#requirements)
- [My framework doesnt seem to be supported, what can I do?](#my-framework-doesnt-seem-to-be-supported-what-can-i-do)
- [How to use](#how-to-use)
- [Setting up the build tool](#setting-up-the-build-tool)
- [Changing just the look of the default Keycloak theme](#changing-just-the-look-of-the-default-keycloak-theme)
- [Changing the look **and** feel](#changing-the-look-and-feel)
- [Hot reload](#hot-reload)
- [Enable loading in a blink of an eye of login pages ⚡ (--external-assets)](#enable-loading-in-a-blink-of-an-eye-of-login-pages----external-assets)
- [Support for Terms and conditions](#support-for-terms-and-conditions)
- [Some pages still have the default theme. Why?](#some-pages-still-have-the-default-theme-why)
- [GitHub Actions](#github-actions)
- [Limitations](#limitations)
- [`process.env.PUBLIC_URL` not supported.](#processenvpublic_url-not-supported)
- [`@font-face` importing fonts from the `src/` dir](#font-face-importing-fonts-from-thesrc-dir)
- [Example of setup that **won't** work](#example-of-setup-that-wont-work)
- [Possible workarounds](#possible-workarounds)
- [Implement context persistence (optional)](#implement-context-persistence-optional)
- [Kickstart video](#kickstart-video)
- [Email domain whitelist](#email-domain-whitelist)
# Requirements
Tested with the following Keycloak versions:
- [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore)
- [12.0.4](https://hub.docker.com/layers/jboss/keycloak/12.0.4/images/sha256-67e0c88e69bd0c7aef972c40bdeb558a974013a28b3668ca790ed63a04d70584?context=explore)
This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get
(before you customize it) will always be the ones of Keycloak v11.
This tool assumes you are bundling your app with Webpack (tested with 4.44.2) .
It assumes there is a `build/` directory at the root of your react project directory containing a `index.html` file
and a `build/static/` directory generated by webpack.
For more information see [this issue](https://github.com/InseeFrLab/keycloakify/issues/5#issuecomment-832296432)
## My framework doesnt seem to be supported, what can I do?
Currently Keycloakify is only compatible with `create-react-app` apps.
It doesnt mean that you can't use Keycloakify if you are using Next.js, Express or any other
framework that involves SSR but your Keycloak theme will need to be a standalone project.
Find specific instructions about how to get started [**here**](https://github.com/garronej/keycloakify-demo-app#keycloak-theme-only).
To share your styles between your main app and your login pages you will need to externalize your design system by making it a
separate module. Checkout [ts_ci](https://github.com/garronej/ts_ci), it can help with that.
# How to use
## Setting up the build tool
Add `keycloak-react-theming` to the dev dependencies of your project `npm install --save-dev keycloak-react-theming` or `yarn add --dev keycloak-react-theming`
then configure your `package.json` build's script to build the keycloak's theme by adding `&& build-keycloak-theme`.
Typically you will get:
`package.json`:
```json
"devDependencies": {
"keycloak-react-theming": "^0.0.10"
},
"scripts": {
"build": "react-scripts build && build-keycloak-theme"
},
```bash
yarn add keycloakify
```
Then build your app with `yarn run build` or `npm run build`, you will be provided with instructions
about how to load the theme into Keycloak.
[`package.json`](https://github.com/garronej/keycloakify-demo-app/blob/main/package.json)
```json
"scripts": {
"keycloak": "yarn build && build-keycloak-theme",
}
```
```bash
yarn keycloak # generates keycloak-theme.jar
```
On the console will be printed all the instructions about how to load the generated theme in Keycloak
### Changing just the look of the default Keycloak theme
The first approach is to only customize the style of the default Keycloak login by providing
your own class names.
If you have created a new React project specifically to create a Keycloak theme and nothing else then
your index should look something like:
`src/index.tsx`
```tsx
import { App } from "./<wherever>/App";
import {
KcApp,
defaultKcProps,
kcContext
} from "keycloakify";
import { css } from "tss-react";
const myClassName = css({ "color": "red" });
reactDom.render(
<KcApp
kcContext={kcContext}
{...{
...defaultKcProps,
"kcHeaderWrapperClass": myClassName
}}
/>
document.getElementById("root")
);
```
If you share a unique project for your app and the Keycloak theme, your index should look
more like this:
`src/index.tsx`
```tsx
import { App } from "./<wherever>/App";
import {
KcApp,
defaultKcProps,
kcContext
} from "keycloakify";
import { css } from "tss-react";
const myClassName = css({ "color": "red" });
reactDom.render(
// Unless the app is currently being served by Keycloak
// kcContext is undefined.
kcContext !== undefined ?
<KcApp
kcContext={kcContext}
{...{
...defaultKcProps,
"kcHeaderWrapperClass": myClassName
}}
/> :
<App />, // Your actual app
document.getElementById("root")
);
```
<p align="center">
<i>result:</i></br>
<img src="https://user-images.githubusercontent.com/6702424/114326299-6892fc00-9b34-11eb-8d75-85696e55458f.png">
</p>
Example of a customization using only CSS: [here](https://github.com/InseeFrLab/onyxia-ui/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/components/KcApp.tsx)
(the [index.tsx](https://github.com/InseeFrLab/onyxia-ui/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/index.tsx#L89-L94) )
and the result you can expect:
<p align="center">
<i> <a href="https://datalab.sspcloud.fr">Customization using only CSS:</a> </i>
<br>
<img src="https://github.com/InseeFrLab/keycloakify/releases/download/v0.3.8/keycloakify_after.gif">
</p>
### Changing the look **and** feel
If you want to really re-implement the pages, the best approach is to
create your own version of the [`<KcApp />`](https://github.com/garronej/keycloakify/blob/develop/src/lib/components/KcApp.tsx).
Copy/past some of [the components](https://github.com/garronej/keycloakify/tree/develop/src/lib/components) provided by this module and start hacking around.
You can find an example of such customization [here](https://github.com/InseeFrLab/onyxia-ui/tree/master/src/app/components/KcApp).
And you can test the result in production by trying the login register page of [Onyxia](https://datalab.sspcloud.fr)
Note that you dont have to re write **all** components, only the ones that you most need customized.
Look at [here for example](https://github.com/InseeFrLab/onyxia-ui/blob/3bf18aa82b198fc6ba7998c30abf0a9ae54a58b1/src/app/components/KcApp/KcApp.tsx#L112-L120).
We want to have our very own login and register page, so we wrote customs [Login.tsx](https://github.com/InseeFrLab/onyxia-ui/blob/master/src/app/components/KcApp/Login.tsx) and [Register.txs](https://github.com/InseeFrLab/onyxia-ui/blob/master/src/app/components/KcApp/Register.tsx), we import them [here](https://github.com/InseeFrLab/onyxia-ui/blob/3bf18aa82b198fc6ba7998c30abf0a9ae54a58b1/src/app/components/KcApp/KcApp.tsx#L9-L10) and use them [here](https://github.com/InseeFrLab/onyxia-ui/blob/3bf18aa82b198fc6ba7998c30abf0a9ae54a58b1/src/app/components/KcApp/KcApp.tsx#L113-L114).
We don't want to bother, however, customizing `login-reset-password.ftl`. We are fine using the component from [the default theme](https://github.com/InseeFrLab/onyxia-ui/blob/3bf18aa82b198fc6ba7998c30abf0a9ae54a58b1/src/app/components/KcApp/KcApp.tsx#L13) with just some [CSS customization](https://github.com/InseeFrLab/onyxia-ui/blob/3bf18aa82b198fc6ba7998c30abf0a9ae54a58b1/src/app/components/KcApp/KcApp.tsx#L103-L110).
WARNING: If you chose to go this way use:
```json
"dependencies": {
"keycloakify": "~X.Y.Z"
}
```
in your `package.json` instead of `^X.Y.Z`. A minor update of Keycloakify might break your app.
### Hot reload
Rebuild the theme each time you make a change to see the result is not practical.
If you want to test your login screens outside of Keycloak, in [storybook](https://storybook.js.org/)
for example you can use `kcContextMocks`.
```tsx
import {
KcApp,
defaultKcProps,
kcContextMocks
} from "keycloakify";
reactDom.render(
<KcApp
kcContext={kcContextMocks.kcLoginContext}
{...defaultKcProps}
/>
document.getElementById("root")
);
```
Then `yarn start`, you will see your login page.
Checkout [this concrete example](https://github.com/garronej/keycloakify-demo-app/blob/main/src/index.tsx)
## Enable loading in a blink of an eye of login pages ⚡ (--external-assets)
By default the theme generated is standalone. Meaning that when your users
reach the login pages all scripts, images and stylesheet are downloaded from the Keycloak server.
If you are specifically building a theme to integrate with an app or a website that allows users
to first browse unauthenticated before logging in, you will get a significant
performance boost if you jump through those hoops:
- Provide the url of your app in the `homepage` field of package.json. [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/package.json#L2)
- Build the theme using `npx build-keycloak-theme --external-assets` [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/.github/workflows/ci.yaml#L21)
- Enable [long-term assets caching](https://create-react-app.dev/docs/production-build/#static-file-caching) on the server hosting your app.
- Make sure not to build your app and the keycloak theme separately
and remember to update the Keycloak theme every time you update your app.
- Be mindful that if your app is down your login pages are down as well.
Checkout a complete setup [here](https://github.com/garronej/keycloakify-demo-app#about-keycloakify)
# Support for Terms and conditions
[Many organizations have a requirement that when a new user logs in for the first time, they need to agree to the terms and conditions of the website.](https://www.keycloak.org/docs/4.8/server_admin/#terms-and-conditions).
First you need to enable the required action on the Keycloak server admin console:
![image](https://user-images.githubusercontent.com/6702424/114280501-dad2e600-9a39-11eb-9c39-a225572dd38a.png)
Then to load your own therms of services using [like this](https://github.com/garronej/keycloakify-demo-app/blob/8168c928a66605f2464f9bd28a4dc85fb0a231f9/src/index.tsx#L42-L66).
# Some pages still have the default theme. Why?
This project only support the most common user facing pages of Keycloak login.
[Here](https://user-images.githubusercontent.com/6702424/116787906-227fe700-aaa7-11eb-92ee-22e7673717c2.png) is the complete list of pages (you get them after running `yarn test`)
and [here](https://github.com/InseeFrLab/keycloakify/tree/main/src/lib/components) are the pages currently implemented by this module.
If you need to customize pages that are not supported yet you can submit an issue about it and wait for me get it implemented.
If you can't wait, PR are welcome! [Here](https://github.com/InseeFrLab/keycloakify/commit/0163459ad6b1ad0afcc34fae5f3cc28dbcf8b4a7) is the commit that adds support
for the `login-otp.ftl` page. You can use it as a model for implementing other pages.
# GitHub Actions
![image](https://user-images.githubusercontent.com/6702424/114286938-47aea600-9a63-11eb-936e-17159e8826e8.png)
[Here is a demo repo](https://github.com/garronej/keycloakify-demo-app) to show how to automate
the building and publishing of the theme (the .jar file).
**All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 4.0.3)
- For building the theme: `mvn` (Maven) must be installed (but you can build the theme in the CI)
- For testing the theme in a local Keycloak container (which is not mandatory for development):
`rm`, `mkdir`, `wget`, `unzip` are assumed to be available and `docker` up and running.
# Limitations
## `process.env.PUBLIC_URL` not supported.
You won't be able to [import things from your public directory **in your JavaScript code**](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system).
(This isn't recommended anyway).
## `@font-face` importing fonts from the `src/` dir
If you are building the theme with [--external-assets](#enable-loading-in-a-blink-of-a-eye-of-login-pages-)
this limitation doesn't apply, you can import fonts however you see fit.
### Example of setup that **won't** work
- We have a `fonts/` directory in `src/`
- We import the font like this [`src: url("/fonts/my-font.woff2") format("woff2");`](https://github.com/garronej/keycloakify-demo-app/blob/07d54a3012ef354ee12b1374c6f7ad1cb125d56b/src/fonts.scss#L4) in a `.scss` a file.
### Possible workarounds
- Use [`--external-assets`](#enable-loading-in-a-blink-of-a-eye-of-login-pages-).
- If it is possible, use Google Fonts or any other font provider.
- If you want to host your font recommended approach is to move your fonts into the `public`
directory and to place your `@font-face` statements in the `public/index.html`.
Example [here](https://github.com/InseeFrLab/onyxia-ui/blob/0e3a04610cfe872ca71dad59e05ced8f785dee4b/public/index.html#L6-L51).
- You can also [use non relative url](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/src/fonts.scss#L16) but don't forget [`Access-Control-Allow-Origin`](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/nginx.conf#L17-L19).
# Implement context persistence (optional)
If, before logging in, a user has selected a specific language
you don't want it to be reset to default when the user gets redirected to
the login or register pages.
Same goes for the dark mode, you don't want, if the user had it enabled
to show the login page with light themes.
The problem is that you are probably using `localStorage` to persist theses values across
reload but, as the Keycloak pages are not served on the same domain that the rest of your
app you won't be able to carry over states using `localStorage`.
The only reliable solution is to inject parameters into the URL before
redirecting to Keycloak. We integrate with
[`keycloak-js`](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc),
by providing you a way to tell `keycloak-js` that you would like to inject
some search parameters before redirecting.
The method also works with [`@react-keycloak/web`](https://www.npmjs.com/package/@react-keycloak/web) (use the `initOptions`).
You can implement your own mechanism to pass the states in the URL and
restore it on the other side but we recommend using `powerhooks/useGlobalState`
from the library [`powerhooks`](https://www.powerhooks.dev) that provide an elegant
way to handle states such as `isDarkModeEnabled` or `selectedLanguage`.
Let's modify [the example](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc) from the official `keycloak-js` documentation to
enables the states of `useGlobalStates` to be injected in the URL before redirecting.
Note that the states are automatically restored on the other side by `powerhooks`
```typescript
import keycloak_js from "keycloak-js";
import { injectGlobalStatesInSearchParams } from "powerhooks/useGlobalState";
import { createKeycloakAdapter } from "keycloakify";
//...
const keycloakInstance = keycloak_js({
"url": "http://keycloak-server/auth",
"realm": "myrealm",
"clientId": "myapp"
});
keycloakInstance.init({
"onLoad": 'check-sso',
"silentCheckSsoRedirectUri": window.location.origin + "/silent-check-sso.html",
"adapter": createKeycloakAdapter({
"transformUrlBeforeRedirect": injectGlobalStatesInSearchParams,
keycloakInstance
})
});
//...
```
If you really want to go the extra miles and avoid having the white
flash of the blank html before the js bundle have been evaluated
[here is a snippet](https://github.com/InseeFrLab/onyxia-ui/blob/a77eb502870cfe6878edd0d956c646d28746d053/public/index.html#L5-L54) that you can place in your `public/index.html` if you are using `powerhooks/useGlobalState`.
# Kickstart video
*NOTE: keycloak-react-theming was renamed keycloakify since this video was recorded*
[![kickstart_video](https://user-images.githubusercontent.com/6702424/108877866-f146ee80-75ff-11eb-8120-003b3c5f6dd8.png)](https://youtu.be/xTz0Rj7i2v8)
## Developing your login and register pages in your React app
# Email domain whitelist
TODO
# How to implement context persistance
If you want dark mode preference, language and others users preferences your can do so
very easily by using [`powerhooks/useGlobalState`](https://github.com/garronej/powerhooks)
WARNING: `powerhooks` is still a work in progress.
# REQUIREMENTS
This tools assumes you are bundling your app with Webpack (tested with 4.44.2) .
It assumes there is a `build/` directory at the root of your react project directory containing a `index.html` file
and a `static/` directory generated by webpack.
**All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 4.0.3=)
- For building the theme: `mvn` (Maven) must be installed
- For development, (testing the theme in a local container ): `rm`, `mkdir`, `wget`, `unzip` are assumed to be available
and `docker` up and running.
NOTE: This build tool has only be tested on MacOS.
# API Reference
## The build tool
Part of the lib that runs with node, at build time.
- `npx build-keycloak-theme`: Builds the theme, the CWD is assumed to be the root of your react project.
- `npx download-sample-keycloak-themes`: Downloads the keycloak default themes (for development purposes)
## The fronted lib ( imported into your react app )
Part of the lib that you import in your react project and runs on the browser.
**TODO**
If you want to restrict the emails domain that can register, you can use [this plugin](https://github.com/micedre/keycloak-mail-whitelisting)
and `kcRegisterContext["authorizedMailDomains"]` to validate on.

View File

@ -1,10 +1,10 @@
{
"name": "keycloak-react-theming",
"version": "0.0.29",
"name": "keycloakify",
"version": "1.0.4",
"description": "Keycloak theme generator for Reacts app",
"repository": {
"type": "git",
"url": "git://github.com/garronej/keycloak-react-theming.git"
"url": "git://github.com/garronej/keycloakify.git"
},
"main": "dist/lib/index.js",
"types": "dist/lib/index.d.ts",
@ -12,15 +12,13 @@
"clean": "rimraf dist/",
"build": "yarn clean && tsc && yarn grant-exec-perms && yarn copy-files",
"grant-exec-perms": "node dist/bin/tools/grant-exec-perms.js",
"test": "node dist/test/build-keycloak-theme.js && node dist/test/download-sample-keycloak-themes.js",
"enable_short_import_path": "yarn build && denoify_enable_short_npm_import_path",
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml dist/",
"generate-messages": "node dist/bin/generate-i18n-messages.js",
"watch": "tsc -w"
"test": "node dist/test",
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml src/**/*.js dist/",
"generate-messages": "node dist/bin/generate-i18n-messages.js"
},
"bin": {
"build-keycloak-theme": "dist/bin/build-keycloak-theme/index.js",
"download-sample-keycloak-themes": "dist/bin/download-sample-keycloak-themes.js"
"install-builtin-keycloak-themes": "dist/bin/install-builtin-keycloak-themes.js"
},
"author": "u/garronej",
"license": "MIT",
@ -40,23 +38,25 @@
"login",
"register"
],
"homepage": "https://github.com/garronej/keycloak-react-theming",
"homepage": "https://github.com/garronej/keycloakify",
"devDependencies": {
"@types/node": "^10.0.0",
"@types/react": "^17.0.0",
"copyfiles": "^2.4.1",
"denoify": "^0.6.5",
"properties-parser": "^0.3.1",
"react": "^17.0.1",
"rimraf": "^3.0.2",
"typescript": "^4.1.5"
"typescript": "^4.2.3"
},
"dependencies": {
"scripting-tools": "^0.19.13",
"cheerio": "^1.0.0-rc.5",
"evt": "^1.9.12",
"evt": "2.0.0-beta.15",
"markdown": "^0.5.0",
"minimal-polyfills": "^2.1.6",
"powerhooks": "^0.0.14",
"tss-react": "^0.0.9"
"path": "^0.12.7",
"powerhooks": "^0.0.36",
"react-markdown": "^5.0.3",
"scripting-tools": "^0.19.13",
"tss-react": "^0.0.12"
}
}

View File

@ -0,0 +1,28 @@
Object.defineProperty(
Object,
"deepAssign",
{
"value": function callee(target, source) {
Object.keys(source).forEach(function (key) {
var value = source[key];
if (target[key] === undefined) {
target[key] = value;
return;
}
if (value instanceof Object) {
if (value instanceof Array) {
value.forEach(function (entry) {
target[key].push(entry);
});
return;
}
callee(target[key], value);
return;
}
target[key] = value;
});
return target;
}
}
);

View File

@ -0,0 +1,26 @@
var es = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
var unes = {
'&amp;': '&',
'&#38;': '&',
'&lt;': '<',
'&#60;': '<',
'&gt;': '>',
'&#62;': '>',
'&apos;': "'",
'&#39;': "'",
'&quot;': '"',
'&#34;': '"'
};
var cape = function (m) { return unes[m]; };
Object.defineProperty(
String,
"htmlUnescape",
{
"value": function (un) {
return String.prototype.replace.call(un, es, cape);
}
}
);

View File

@ -0,0 +1,263 @@
<script>const _=
{
"url": {
"loginAction": (function (){
<#attempt>
return "${url.loginAction?no_esc}";
<#recover>
</#attempt>
})(),
"resourcesPath": (function (){
<#attempt>
return "${url.resourcesPath?no_esc}";
<#recover>
</#attempt>
})(),
"resourcesCommonPath": (function (){
<#attempt>
return "${url.resourcesCommonPath?no_esc}";
<#recover>
</#attempt>
})(),
"loginRestartFlowUrl": (function (){
<#attempt>
return "${url.loginRestartFlowUrl?no_esc}";
<#recover>
</#attempt>
})(),
"loginUrl": (function (){
<#attempt>
return "${url.loginUrl?no_esc}";
<#recover>
</#attempt>
})()
},
"realm": {
"displayName": (function (){
<#attempt>
return "${realm.displayName!''}" || undefined;
<#recover>
</#attempt>
})(),
"displayNameHtml": (function (){
<#attempt>
return "${realm.displayNameHtml!''}" || undefined;
<#recover>
</#attempt>
})(),
"internationalizationEnabled": (function (){
<#attempt>
return ${realm.internationalizationEnabled?c};
<#recover>
</#attempt>
})(),
"registrationEmailAsUsername": (function (){
<#attempt>
return ${realm.registrationEmailAsUsername?c};
<#recover>
</#attempt>
})()
},
"locale": (function (){
<#attempt>
<#if realm.internationalizationEnabled>
return {
"supported": (function(){
var out= [];
<#attempt>
<#list locale.supported as lng>
out.push({
"url": (function (){
<#attempt>
return "${lng.url?no_esc}";
<#recover>
</#attempt>
})(),
"label": (function (){
<#attempt>
return "${lng.label}";
<#recover>
</#attempt>
})(),
"languageTag": (function (){
<#attempt>
return "${lng.languageTag}";
<#recover>
</#attempt>
})()
});
</#list>
<#recover>
</#attempt>
return out;
})(),
"current": (function (){
<#attempt>
return "${locale.current}";
<#recover>
</#attempt>
})()
};
</#if>
<#recover>
</#attempt>
})(),
"auth": (function (){
<#attempt>
<#if auth?has_content>
var out= {
"showUsername": (function (){
<#attempt>
return ${auth.showUsername()?c};
<#recover>
</#attempt>
})(),
"showResetCredentials": (function (){
<#attempt>
return ${auth.showResetCredentials()?c};
<#recover>
</#attempt>
})(),
"showTryAnotherWayLink": (function(){
<#attempt>
return ${auth.showTryAnotherWayLink()?c};
<#recover>
</#attempt>
})()
};
<#attempt>
<#if auth.showUsername() && !auth.showResetCredentials()>
Object.assign(
out,
{
"attemptedUsername": (function (){
<#attempt>
return "${auth.attemptedUsername}";
<#recover>
</#attempt>
})()
}
);
</#if>
<#recover>
</#attempt>
return out;
</#if>
<#recover>
</#attempt>
})(),
"scripts": (function(){
var out = [];
<#attempt>
<#if scripts??>
<#attempt>
<#list scripts as script>
out.push((function (){
<#attempt>
return "${script}";
<#recover>
</#attempt>
})());
</#list>
<#recover>
</#attempt>
</#if>
<#recover>
</#attempt>
return out;
})(),
"message": (function (){
<#attempt>
<#if message?has_content>
return { 
"type": (function (){
<#attempt>
return "${message.type}";
<#recover>
</#attempt>
})(),
"summary": (function (){
<#attempt>
return String.htmlUnescape("${message.summary}");
<#recover>
</#attempt>
})()
};
</#if>
<#recover>
</#attempt>
})(),
"isAppInitiatedAction": (function (){
<#attempt>
<#if isAppInitiatedAction??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})()
}
</script>

View File

@ -0,0 +1,23 @@
<script>const _=
{
"client": (function (){
<#attempt>
<#if client??>
return {
"baseUrl": (function (){
<#attempt>
return "${(client.baseUrl!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})()
};
</#if>
<#recover>
</#attempt>
})()
}
</script>

View File

@ -1,173 +0,0 @@
<script>const _=
{
"url": {
"loginAction": "${url.loginAction}",
"resourcesPath": "${url.resourcesPath}",
"resourcesCommonPath": "${url.resourcesCommonPath}",
"loginRestartFlowUrl": "${url.loginRestartFlowUrl}",
"loginResetCredentialsUrl": "${url.loginResetCredentialsUrl}",
"registrationUrl": "${url.registrationUrl}"
},
"realm": {
"displayName": "${realm.displayName!''}" || undefined,
"displayNameHtml": "${realm.displayNameHtml!''}" || undefined,
"internationalizationEnabled": ${realm.internationalizationEnabled?c},
"password": ${realm.password?c},
"loginWithEmailAllowed": ${realm.loginWithEmailAllowed?c},
"registrationEmailAsUsername": ${realm.registrationEmailAsUsername?c},
"rememberMe": ${realm.rememberMe?c},
"resetPasswordAllowed": ${realm.resetPasswordAllowed?c}
},
"locale": (function (){
<#if realm.internationalizationEnabled>
return {
"supported": (function(){
<#if realm.internationalizationEnabled>
var out= [];
<#list locale.supported as lng>
out.push({
"url": "${lng.url}",
"label": "${lng.label}",
"languageTag": "${lng.languageTag}"
});
</#list>
return out;
</#if>
return undefined;
})(),
"current": "${locale.current}"
};
</#if>
return undefined;
})(),
"auth": (function (){
<#if auth?has_content>
var out= {
"showUsername": ${auth.showUsername()?c},
"showResetCredentials": ${auth.showResetCredentials()?c},
"showTryAnotherWayLink": ${auth.showTryAnotherWayLink()?c},
"selectedCredential": "${auth.selectedCredential!''}" || undefined
};
<#if auth.showUsername() && !auth.showResetCredentials()>
Object.assign(
out,
{
"attemptedUsername": "${auth.attemptedUsername}"
}
);
</#if>
return out;
</#if>
return undefined;
})(),
"scripts": (function(){
var out = [];
<#if scripts??>
<#list scripts as script>
out.push("${script}");
</#list>
</#if>
return out;
})(),
"message": (function (){
<#if message?has_content>
return { 
"type": "${message.type}",
"summary": "${kcSanitize(message.summary)?no_esc}"
};
</#if>
return undefined;
})(),
"isAppInitiatedAction": (function (){
<#if isAppInitiatedAction??>
return true;
</#if>
return false;
})(),
"social": {
"displayInfo": ${social.displayInfo?c},
"providers": (()=>{
<#if social.providers??>
var out= [];
<#list social.providers as p>
out.push({
"loginUrl": "${p.loginUrl}",
"alias": "${p.alias}",
"providerId": "${p.providerId}",
"displayName": "${p.displayName}"
});
</#list>
return out;
</#if>
return undefined;
})()
},
"usernameEditDisabled": (function () {
<#if usernameEditDisabled??>
return true;
</#if>
return false;
})(),
"login": {
"username": "${login.username!''}" || undefined,
"rememberMe": (function (){
<#if login.rememberMe??>
return true;
</#if>
return false;
})()
},
"registrationDisabled": (function (){
<#if registrationDisabled??>
return true;
</#if>
return false;
})
}
</script>

View File

@ -2,36 +2,76 @@
import cheerio from "cheerio";
import {
replaceImportFromStaticInJsCode,
replaceImportsFromStaticInJsCode,
replaceImportsInInlineCssCode,
generateCssCodeToDefineGlobals
} from "../replaceImportFromStatic";
import fs from "fs";
import { join as pathJoin } from "path";
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
export const pageIds = [
"login.ftl", "register.ftl", "info.ftl",
"error.ftl", "login-reset-password.ftl",
"login-verify-email.ftl", "terms.ftl",
"login-otp.ftl"
] as const;
export type PageId = typeof pageIds[number];
function loadAdjacentFile(fileBasename: string) {
return fs.readFileSync(pathJoin(__dirname, fileBasename))
.toString("utf8");
};
function loadFtlFile(ftlFileBasename: PageId | "common.ftl") {
try {
return loadAdjacentFile(ftlFileBasename)
.match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1];
} catch {
return "{}";
}
}
export function generateFtlFilesCodeFactory(
params: {
ftlValuesGlobalName: string;
cssGlobalsToDefine: Record<string, string>;
indexHtmlCode: string;
urlPathname: string;
urlOrigin: undefined | string;
}
) {
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode } = params;
const { cssGlobalsToDefine, indexHtmlCode, urlPathname, urlOrigin } = params;
const $ = cheerio.load(indexHtmlCode);
$("script:not([src])").each((...[, element]) => {
const { fixedJsCode } = replaceImportFromStaticInJsCode({
ftlValuesGlobalName,
"jsCode": $(element).html()!
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": $(element).html()!,
urlOrigin
});
$(element).text(fixedJsCode);
});
$("style").each((...[, element]) => {
const { fixedCssCode } = replaceImportsInInlineCssCode({
"cssCode": $(element).html()!,
"urlPathname": params.urlPathname,
urlOrigin
});
$(element).text(fixedCssCode);
});
([
["link", "href"],
@ -41,78 +81,103 @@ export function generateFtlFilesCodeFactory(
const href = $(element).attr(attrName);
if (!href?.startsWith("/")) {
if (href === undefined) {
return;
}
$(element).attr(attrName, "${url.resourcesPath}/build" + href);
$(element).attr(
attrName,
urlOrigin !== undefined ?
href.replace(/^\//, `${urlOrigin}/`) :
href.replace(
new RegExp(`^${urlPathname.replace(/\//g, "\\/")}`),
"${url.resourcesPath}/build/"
)
);
})
);
//FTL is no valid html, we can't insert with cheerio, we put placeholder for injecting later.
const ftlPlaceholders = {
'{ "x": "xIdLqMeOed9sdLdIdOxdK0d" }':
fs.readFileSync(pathJoin(__dirname, "ftl2js.ftl"))
.toString("utf8")
.match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1],
const ftlCommonPlaceholders = {
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': loadFtlFile("common.ftl"),
'<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->':
[
'<#if scripts??>',
' <#list scripts as script>',
' <script src="${script}" type="text/javascript"></script>',
' </#list>',
'</#if>',
'</#if>'
].join("\n")
};
const pageSpecificCodePlaceholder = "<!-- dIddLqMeOedErIdLsPdNdI9dSl42sw -->";
$("head").prepend(
[
...(Object.keys(cssGlobalsToDefine).length === 0 ? [] : [
'',
'<style>',
generateCssCodeToDefineGlobals(
{ cssGlobalsToDefine }
).cssCodeToPrependInHead,
generateCssCodeToDefineGlobals({
cssGlobalsToDefine,
urlPathname
}).cssCodeToPrependInHead,
'</style>',
''
]),
...["Object.deepAssign.js", "String.htmlUnescape.js"].map(
fileBasename => [
"<script>",
loadAdjacentFile(fileBasename),
"</script>"
].join("\n")
),
'<script>',
' Object.assign(',
` window.${ftlValuesGlobalName},`,
` ${objectKeys(ftlPlaceholders)[0]}`,
` window.${ftlValuesGlobalName}= Object.assign(`,
` {},`,
` ${objectKeys(ftlCommonPlaceholders)[0]}`,
' );',
'</script>',
'',
objectKeys(ftlPlaceholders)[1],
''
pageSpecificCodePlaceholder,
'',
objectKeys(ftlCommonPlaceholders)[1]
].join("\n"),
);
const partiallyFixedIndexHtmlCode = $.html();
function generateFtlFilesCode(
params: {
pageBasename: "login.ftl" | "register.ftl"
pageId: PageId;
}
): { ftlCode: string; } {
const { pageBasename } = params;
const { pageId } = params;
const $ = cheerio.load(partiallyFixedIndexHtmlCode);
$("head").prepend(
[
'',
'<script>',
` window.${ftlValuesGlobalName} = { "pageBasename": "${pageBasename}" };`,
'</script>',
''
].join("\n")
);
const ftlPlaceholders = {
'{ "x": "kxOlLqMeOed9sdLdIdOxd444" }': loadFtlFile(pageId),
...ftlCommonPlaceholders
};
let ftlCode = $.html();
let ftlCode = $.html()
.replace(
pageSpecificCodePlaceholder,
[
'<script>',
` Object.deepAssign(`,
` window.${ftlValuesGlobalName},`,
` { "pageId": "${pageId}" }`,
' );',
` Object.deepAssign(`,
` window.${ftlValuesGlobalName},`,
` ${objectKeys(ftlPlaceholders)[0]}`,
' );',
'</script>'
].join("\n")
);
objectKeys(ftlPlaceholders)
.forEach(id => ftlCode = ftlCode.replace(id, ftlPlaceholders[id]));

View File

@ -0,0 +1,82 @@
<script>const _=
{
"messageHeader": (function (){
<#attempt>
return "${messageHeader!''}" || undefined;
<#recover>
</#attempt>
})(),
"requiredActions": (function (){
<#attempt>
<#if requiredActions??>
var out =[];
<#attempt>
<#list requiredActions>
<#attempt>
<#items as reqActionItem>
out.push((function (){
<#attempt>
return "${reqActionItem}";
<#recover>
</#attempt>
})());
</#items>
<#recover>
</#attempt>
</#list>
<#recover>
</#attempt>
return out;
</#if>
<#recover>
</#attempt>
})(),
"skipLink": (function (){
<#attempt>
<#if skipLink??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"pageRedirectUri": (function (){
<#attempt>
return "${(pageRedirectUri!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})(),
"actionUri": (function (){
<#attempt>
return "${(actionUri!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})(),
"client": {
"baseUrl": (function(){
<#attempt>
return "${(client.baseUrl!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})()
}
}
</script>

View File

@ -0,0 +1,37 @@
<script>const _=
{
"otpLogin": {
"userOtpCredentials": (function(){
var out = [];
<#attempt>
<#list otpLogin.userOtpCredentials as otpCredential>
out.push({
"id": (function (){
<#attempt>
return "${otpCredential.id}";
<#recover>
</#attempt>
})(),
"userLabel": (function (){
<#attempt>
return "${otpCredential.userLabel}";
<#recover>
</#attempt>
})()
});
</#list>
<#recover>
</#attempt>
return out;
})()
}
}
</script>

View File

@ -0,0 +1,14 @@
<script>const _=
{
"realm": {
"loginWithEmailAllowed": (function (){
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
})()
}
}
</script>

View File

@ -0,0 +1,160 @@
<script>const _=
{
"url": {
"loginResetCredentialsUrl": (function (){
<#attempt>
return "${url.loginResetCredentialsUrl?no_esc}";
<#recover>
</#attempt>
})(),
"registrationUrl": (function (){
<#attempt>
return "${url.registrationUrl?no_esc}";
<#recover>
</#attempt>
})()
},
"realm": {
"loginWithEmailAllowed": (function(){
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
})(),
"rememberMe": (function (){
<#attempt>
return ${realm.rememberMe?c};
<#recover>
</#attempt>
})(),
"password": (function (){
<#attempt>
return ${realm.password?c};
<#recover>
</#attempt>
})(),
"resetPasswordAllowed": (function (){
<#attempt>
return ${realm.resetPasswordAllowed?c};
<#recover>
</#attempt>
})(),
"registrationAllowed": (function (){
<#attempt>
return ${realm.registrationAllowed?c};
<#recover>
</#attempt>
})()
},
"auth": (function (){
<#attempt>
<#if auth?has_content>
return {
"selectedCredential": (function (){
<#attempt>
return "${auth.selectedCredential!''}" || undefined;
<#recover>
</#attempt>
})()
};
</#if>
<#recover>
</#attempt>
})(),
"social": {
"displayInfo": (function (){
<#attempt>
return ${social.displayInfo?c};
<#recover>
</#attempt>
})(),
"providers": (()=>{
<#attempt>
<#if social.providers??>
var out= [];
<#attempt>
<#list social.providers as p>
out.push({
"loginUrl": (function (){
<#attempt>
return "${p.loginUrl?no_esc}";
<#recover>
</#attempt>
})(),
"alias": (function (){
<#attempt>
return "${p.alias}";
<#recover>
</#attempt>
})(),
"providerId": (function (){
<#attempt>
return "${p.providerId}";
<#recover>
</#attempt>
})(),
"displayName": (function (){
<#attempt>
return "${p.displayName}";
<#recover>
</#attempt>
})()
});
</#list>
<#recover>
</#attempt>
return out;
</#if>
<#recover>
</#attempt>
})()
},
"usernameEditDisabled": (function () {
<#attempt>
<#if usernameEditDisabled??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"login": {
"username": (function (){
<#attempt>
return "${login.username!''}" || undefined;
<#recover>
</#attempt>
})(),
"rememberMe": (function (){
<#attempt>
<#if login.rememberMe??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})()
},
"registrationDisabled": (function (){
<#attempt>
<#if registrationDisabled??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})()
}
</script>

View File

@ -0,0 +1,189 @@
<script>const _=
{
"url": {
"registrationAction": (function (){
<#attempt>
return "${url.registrationAction?no_esc}";
<#recover>
</#attempt>
})()
},
"messagesPerField": {
"printIfExists": function (key, x) {
switch(key){
case "userLabel": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('userLabel','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "username": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('username','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "email": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('email','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "firstName": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('firstName','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "lastName": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('lastName','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "password": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('password','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "password-confirm": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('password-confirm','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
}
}
},
"register": {
"formData": {
"firstName": (function (){
<#attempt>
return "${register.formData.firstName!''}" || undefined;
<#recover>
</#attempt>
})(),
"displayName": (function (){
<#attempt>
return "${register.formData.displayName!''}" || undefined;
<#recover>
</#attempt>
})(),
"lastName": (function (){
<#attempt>
return "${register.formData.lastName!''}" || undefined;
<#recover>
</#attempt>
})(),
"email": (function(){
<#attempt>
return "${register.formData.email!''}" || undefined;
<#recover>
</#attempt>
})(),
"username": (function (){
<#attempt>
return "${register.formData.username!''}" || undefined;
<#recover>
</#attempt>
})()
}
},
"passwordRequired": (function (){
<#attempt>
<#if passwordRequired??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"recaptchaRequired": (function (){
<#attempt>
<#if passwordRequired??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"recaptchaSiteKey": (function (){
<#attempt>
return "${recaptchaSiteKey!''}" || undefined;
<#recover>
</#attempt>
})(),
"authorizedMailDomains": (function (){
<#attempt>
return "${authorizedMailDomains!''}" || undefined;
<#recover>
</#attempt>
})(),
"authorizedMailDomains": (function(){
var out = undefined;
<#attempt>
<#if authorizedMailDomains??>
out = [];
<#attempt>
<#list authorizedMailDomains as authorizedMailDomain>
out.push((function (){
<#attempt>
return "${authorizedMailDomain}";
<#recover>
</#attempt>
})());
</#list>
<#recover>
</#attempt>
</#if>
<#recover>
</#attempt>
return out;
})(),
}
</script>

View File

@ -32,7 +32,7 @@ export function generateJavaStackFiles(
return (!homepage ?
fallbackGroupId :
url.parse(homepage).host?.split(".").reverse().join(".") ?? fallbackGroupId
url.parse(homepage).host?.replace(/:[0-9]+$/,"")?.split(".").reverse().join(".") ?? fallbackGroupId
) + ".keycloak";
})();

View File

@ -3,37 +3,56 @@ import { transformCodebase } from "../tools/transformCodebase";
import * as fs from "fs";
import { join as pathJoin } from "path";
import {
replaceImportFromStaticInCssCode,
replaceImportFromStaticInJsCode
replaceImportsInCssCode,
replaceImportsFromStaticInJsCode
} from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory } from "./generateFtl";
import { keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl } from "../download-sample-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import * as child_process from "child_process";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside";
export function generateKeycloakThemeResources(
params: {
themeName: string;
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
urlPathname: string;
//If urlOrigin is not undefined then it means --externals-assets
urlOrigin: undefined | string;
}
) {
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath } = params;
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, urlPathname, urlOrigin } = params;
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
let allCssGlobalsToDefine: Record<string, string> = {};
transformCodebase({
"destDirPath": pathJoin(themeDirPath, "resources", "build"),
"destDirPath":
urlOrigin === undefined ?
pathJoin(themeDirPath, "resources", "build") :
reactAppBuildDirPath,
"srcDirPath": reactAppBuildDirPath,
"transformSourceCode": ({ filePath, sourceCode }) => {
if (/\.css?$/i.test(filePath)) {
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
if (
urlOrigin === undefined &&
isInside({
"dirPath": pathJoin(reactAppBuildDirPath, subDirOfPublicDirBasename),
filePath
})
) {
return undefined;
}
const { cssGlobalsToDefine, fixedCssCode } = replaceImportFromStaticInCssCode(
if (urlOrigin === undefined && /\.css?$/i.test(filePath)) {
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode(
{ "cssCode": sourceCode.toString("utf8") }
);
@ -48,36 +67,41 @@ export function generateKeycloakThemeResources(
if (/\.js?$/i.test(filePath)) {
const { fixedJsCode } = replaceImportFromStaticInJsCode({
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"),
ftlValuesGlobalName
urlOrigin
});
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
}
return { "modifiedSourceCode": sourceCode };
return urlOrigin === undefined ?
{ "modifiedSourceCode": sourceCode } :
undefined;
}
});
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
"cssGlobalsToDefine": allCssGlobalsToDefine,
ftlValuesGlobalName,
"indexHtmlCode": fs.readFileSync(
pathJoin(reactAppBuildDirPath, "index.html")
).toString("utf8")
).toString("utf8"),
urlPathname,
urlOrigin
});
(["login.ftl", "register.ftl"] as const).forEach(pageBasename => {
pageIds.forEach(pageId => {
const { ftlCode } = generateFtlFilesCode({ pageBasename });
const { ftlCode } = generateFtlFilesCode({ pageId });
fs.mkdirSync(themeDirPath, { "recursive": true });
fs.writeFileSync(
pathJoin(themeDirPath, pageBasename),
pathJoin(themeDirPath, pageId),
Buffer.from(ftlCode, "utf8")
)
);
});
@ -86,30 +110,59 @@ export function generateKeycloakThemeResources(
const tmpDirPath = pathJoin(themeDirPath, "..", "tmp_xxKdLpdIdLd");
downloadAndUnzip({
"url": keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl,
"url": builtinThemesUrl,
"destDirPath": tmpDirPath
});
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common"),
"destDirPath": pathJoin(tmpDirPath, "..", "common")
});
const themeResourcesDirPath = pathJoin(themeDirPath, "resources");
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "login", "resources"),
"destDirPath": pathJoin(themeDirPath, "resources")
"destDirPath": themeResourcesDirPath
});
const reactAppPublicDirPath = pathJoin(reactAppBuildDirPath, "..", "public");
transformCodebase({
"srcDirPath": themeResourcesDirPath,
"destDirPath": pathJoin(
reactAppPublicDirPath,
resourcesPath
)
});
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"),
"destDirPath": pathJoin(
reactAppPublicDirPath,
resourcesCommonPath
)
});
const keycloakResourcesWithinPublicDirPath =
pathJoin(reactAppPublicDirPath, subDirOfPublicDirBasename);
fs.writeFileSync(
pathJoin(keycloakResourcesWithinPublicDirPath, "README.txt"),
Buffer.from([
"This is just a test folder that helps develop",
"the login and register page without having to yarn build"
].join(" "))
);
fs.writeFileSync(
pathJoin(keycloakResourcesWithinPublicDirPath, ".gitignore"),
Buffer.from("*", "utf8")
);
child_process.execSync(`rm -r ${tmpDirPath}`);
}
fs.writeFileSync(
pathJoin(themeDirPath, "theme.properties"),
Buffer.from([
`[import=common/${themeName}`,
"locales=ca,cs,de,en,es,fr,it,ja,lt,nl,no,pl,pt-BR,ru,sk,sv,tr,zh-CN"
].join("\n"), "utf8")
Buffer.from("parent=keycloak", "utf8")
);
}

View File

@ -6,10 +6,13 @@ import type { ParsedPackageJson } from "./generateJavaStackFiles";
import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process";
import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles";
import { URL } from "url";
const reactProjectDirPath = process.cwd();
const doUseExternalAssets = process.argv[2]?.toLowerCase() === "--external-assets";
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
@ -22,7 +25,38 @@ if (require.main === module) {
generateKeycloakThemeResources({
keycloakThemeBuildingDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
"themeName": parsedPackageJson.name
"themeName": parsedPackageJson.name,
...(() => {
const url = (() => {
const { homepage } = parsedPackageJson;
return homepage === undefined ?
undefined :
new URL(homepage);
})();
return {
"urlPathname":
url === undefined ?
"/" :
url.pathname.replace(/([^/])$/, "$1/"),
"urlOrigin": !doUseExternalAssets ? undefined : (() => {
if (url === undefined) {
console.error("ERROR: You must specify 'homepage' in your package.json");
process.exit(-1);
}
return url.origin;
})()
};
})()
});
const { jarFilePath } = generateJavaStackFiles({

View File

@ -1,25 +1,52 @@
import * as crypto from "crypto";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
export function replaceImportFromStaticInJsCode(
export function replaceImportsFromStaticInJsCode(
params: {
ftlValuesGlobalName: string;
jsCode: string;
urlOrigin: undefined | string;
}
): { fixedJsCode: string; } {
const { jsCode, ftlValuesGlobalName } = params;
const { jsCode, urlOrigin } = params;
const fixedJsCode = jsCode!.replace(
/"static\//g,
`window.${ftlValuesGlobalName}.url.resourcesPath.replace(/^\\//,"") + "/build/static/`
const fixedJsCode = jsCode.replace(
/([a-z]+\.[a-z]+)\+"static\//g,
(...[, group]) =>
urlOrigin === undefined ?
`window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/` :
`("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group} + "static/`
);
return { fixedJsCode };
}
export function replaceImportFromStaticInCssCode(
export function replaceImportsInInlineCssCode(
params: {
cssCode: string;
urlPathname: string;
urlOrigin: undefined | string;
}
): { fixedCssCode: string; } {
const { cssCode, urlPathname, urlOrigin } = params;
const fixedCssCode = cssCode.replace(
urlPathname === "/" ?
/url\(\/([^/][^)]+)\)/g :
new RegExp(`url\\(${urlPathname}([^)]+)\\)`, "g"),
(...[, group]) => `url(${urlOrigin === undefined ?
"${url.resourcesPath}/build/" + group :
params.urlOrigin + urlPathname + group})`
);
return { fixedCssCode };
}
export function replaceImportsInCssCode(
params: {
cssCode: string;
}
@ -32,7 +59,7 @@ export function replaceImportFromStaticInCssCode(
const cssGlobalsToDefine: Record<string, string> = {};
new Set(cssCode.match(/(url\(\/[^)]+\))/g) ?? [])
new Set(cssCode.match(/url\(\/[^/][^)]+\)[^;}]*/g) ?? [])
.forEach(match =>
cssGlobalsToDefine[
"url" + crypto
@ -60,12 +87,13 @@ export function replaceImportFromStaticInCssCode(
export function generateCssCodeToDefineGlobals(
params: {
cssGlobalsToDefine: Record<string, string>;
urlPathname: string;
}
): {
cssCodeToPrependInHead: string;
} {
const { cssGlobalsToDefine } = params;
const { cssGlobalsToDefine, urlPathname } = params;
return {
"cssCodeToPrependInHead": [
@ -73,12 +101,8 @@ export function generateCssCodeToDefineGlobals(
...Object.keys(cssGlobalsToDefine)
.map(cssVariableName => [
`--${cssVariableName}:`,
[
"url(",
"${url.resourcesPath}/build" +
cssGlobalsToDefine[cssVariableName].match(/^url\(([^)]+)\)$/)![1],
")"
].join("")
cssGlobalsToDefine[cssVariableName]
.replace(new RegExp(`url\\(${urlPathname.replace(/\//g, "\\/")}`, "g"), "url(${url.resourcesPath}/build/")
].join(" "))
.map(line => ` ${line};`),
"}"

View File

@ -1,8 +1,9 @@
import "minimal-polyfills/Object.fromEntries";
import * as fs from "fs";
import { join as pathJoin, relative as pathRelative } from "path";
import { crawl } from "./tools/crawl";
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
import { keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl } from "./download-sample-keycloak-themes";
import { builtinThemesUrl } from "./install-builtin-keycloak-themes";
import { getProjectRoot } from "./tools/getProjectRoot";
import * as child_process from "child_process";
@ -15,7 +16,7 @@ child_process.execSync(`rm -rf ${tmpDirPath}`);
downloadAndUnzip({
"destDirPath": tmpDirPath,
"url": keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl
"url": builtinThemesUrl
});
type Dictionary = { [idiomId: string]: string };
@ -34,17 +35,21 @@ crawl(".").forEach(filePath => {
const [, typeOfPage, language] = match;
(record[typeOfPage] ??= {})[language.replace(/_/g,"-")] =
propertiesParser.parse(
fs.readFileSync(filePath)
.toString("utf8")
(record[typeOfPage] ??= {})[language.replace(/_/g, "-")] =
Object.fromEntries(
Object.entries(
propertiesParser.parse(
fs.readFileSync(filePath)
.toString("utf8")
)
).map(([key, value]: any) => [key, value.replace(/''/g, "'")])
);
});
child_process.execSync(`rm -r ${tmpDirPath}`);
const targetDirPath = pathJoin(getProjectRoot(), "src", "lib", "i18n", "generated_messages");
const targetDirPath = pathJoin(getProjectRoot(), "src", "lib", "i18n", "generated_kcMessages");
fs.mkdirSync(targetDirPath, { "recursive": true });
@ -60,7 +65,7 @@ Object.keys(record).forEach(pageType => {
'//PLEASE DO NOT EDIT MANUALLY',
'',
'/* spell-checker: disable */',
`export const messages= ${JSON.stringify(record[pageType], null, 2)} as const;`,
`export const kcMessages= ${JSON.stringify(record[pageType], null, 2)};`,
'/* spell-checker: enable */'
].join("\n"), "utf8")
);

View File

@ -4,13 +4,13 @@ import { keycloakThemeBuildingDirPath } from "./build-keycloak-theme";
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
import { join as pathJoin } from "path";
export const keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl =
"https://github.com/garronej/keycloak-react-theming/releases/download/v0.0.1/other_keycloak_thems.zip";
export const builtinThemesUrl =
"https://github.com/garronej/keycloakify/releases/download/v0.0.1/keycloak_11.0.3_builtin_themes_with_light_mods.zip";
if (require.main === module) {
downloadAndUnzip({
"url": keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl,
"url": builtinThemesUrl,
"destDirPath": pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme")
});

14
src/bin/tools/isInside.ts Normal file
View File

@ -0,0 +1,14 @@
import { relative as pathRelative } from "path";
export function isInside(
params: {
dirPath: string;
filePath: string;
}
) {
const { dirPath, filePath } = params;
return !pathRelative(dirPath, filePath).startsWith("..");
}

View File

@ -0,0 +1,39 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import { assert } from "../tools/assert";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
export const Error = memo(({ kcContext, ...props }: { kcContext: KcContext.Error; } & KcProps) => {
const { msg } = useKcMessage();
assert(kcContext.message !== undefined);
const { message, client } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
displayMessage={false}
headerNode={msg("errorTitle")}
formNode={
<div id="kc-error-message">
<p className="instruction">{message.summary}</p>
{
client !== undefined && client.baseUrl !== undefined &&
<p>
<a id="backToApplication" href={client.baseUrl}>
{msg("backToApplication")}
</a>
</p>
}
</div>
}
/>
);
});

View File

@ -0,0 +1,72 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import { assert } from "../tools/assert";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
export const Info = memo(({ kcContext, ...props }: { kcContext: KcContext.Info; } & KcProps) => {
const { msg } = useKcMessage();
assert(kcContext.message !== undefined);
const {
messageHeader,
message,
requiredActions,
skipLink,
pageRedirectUri,
actionUri,
client
} = kcContext;
return (
<Template
{...{ kcContext, ...props }}
displayMessage={false}
headerNode={
messageHeader !== undefined ?
<>{messageHeader}</>
:
<>{message.summary}</>
}
formNode={
<div id="kc-info-message">
<p className="instruction">{message.summary}
{
requiredActions !== undefined &&
<b>
{
requiredActions
.map(requiredAction => msg(`requiredAction.${requiredAction}` as const))
.join(",")
}
</b>
}
</p>
{
!skipLink &&
pageRedirectUri !== undefined ?
<p><a href={pageRedirectUri}>{(msg("backToApplication"))}</a></p>
:
actionUri !== undefined ?
<p><a href={actionUri}>{msg("proceedWithAction")}</a></p>
:
client.baseUrl !== undefined &&
<p><a href={client.baseUrl}>{msg("backToApplication")}</a></p>
}
</div>
}
/>
);
});

View File

@ -1,25 +1,25 @@
import { memo } from "react";
import { kcContext } from "../kcContext";
import { assert } from "evt/tools/typeSafety/assert";
import type { KcPagesProperties } from "./KcProperties";
import type { KcContext } from "../KcContext";
import type { KcProps } from "./KcProps";
import { Login } from "./Login";
import { Register } from "./Register";
import { Info } from "./Info";
import { Error } from "./Error";
import { LoginResetPassword } from "./LoginResetPassword";
import { LoginVerifyEmail } from "./LoginVerifyEmail";
import { Terms } from "./Terms";
import { LoginOtp } from "./LoginOtp";
export type KcAppProps = {
kcProperties?: KcPagesProperties;
};
export const KcApp = memo((props: KcAppProps) => {
const { kcProperties } = props;
assert(kcContext !== undefined, "App is not currently served by a Keycloak server");
switch (kcContext.pageBasename) {
case "login.ftl": return <Login kcProperties={kcProperties} />
case "register.ftl":
alert(`TODO: Implement ${kcContext.pageBasename}`);
return null;
export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContext; } & KcProps ) => {
switch (kcContext.pageId) {
case "login.ftl": return <Login {...{ kcContext, ...props }} />;
case "register.ftl": return <Register {...{ kcContext, ...props }} />;
case "info.ftl": return <Info {...{ kcContext, ...props }} />;
case "error.ftl": return <Error {...{ kcContext, ...props }} />;
case "login-reset-password.ftl": return <LoginResetPassword {...{ kcContext, ...props }} />;
case "login-verify-email.ftl": return <LoginVerifyEmail {...{ kcContext, ...props }} />;
case "terms.ftl": return <Terms {...{ kcContext, ...props }}/>;
case "login-otp.ftl": return <LoginOtp {...{ kcContext, ...props }}/>;
}
});

View File

@ -1,192 +0,0 @@
import { allPropertiesValuesToUndefined } from "../tools/allPropertiesValuesToUndefined";
/** Class names can be provided as an array or separated by whitespace */
export type KcClasses<CssClasses extends string> = { [key in CssClasses]?: string[] | string };
export type KcTemplateCssClasses =
"kcHtmlClass" |
"kcLoginClass" |
"kcHeaderClass" |
"kcHeaderWrapperClass" |
"kcFormCardClass" |
"kcFormCardAccountClass" |
"kcFormHeaderClass" |
"kcLocaleWrapperClass" |
"kcContentWrapperClass" |
"kcLabelWrapperClass" |
"kcContentWrapperClass" |
"kcLabelWrapperClass" |
"kcFormGroupClass" |
"kcResetFlowIcon" |
"kcResetFlowIcon" |
"kcFeedbackSuccessIcon" |
"kcFeedbackWarningIcon" |
"kcFeedbackErrorIcon" |
"kcFeedbackInfoIcon" |
"kcContentWrapperClass" |
"kcFormSocialAccountContentClass" |
"kcFormSocialAccountClass" |
"kcSignUpClass" |
"kcInfoAreaWrapperClass"
;
export type KcTemplateProperties = {
stylesCommon?: string[];
styles?: string[];
scripts?: string[];
} & KcClasses<KcTemplateCssClasses>;
export const defaultKcTemplateProperties: KcTemplateProperties = {
"styles": ["css/login.css"],
"stylesCommon": [
...[".min.css", "-additions.min.css"]
.map(end => `node_modules/patternfly/dist/css/patternfly${end}`),
"lib/zocial/zocial.css"
],
"kcHtmlClass": "login-pf",
"kcLoginClass": "login-pf-page",
"kcContentWrapperClass": "row",
"kcHeaderClass": "login-pf-page-header",
"kcFormCardClass": "card-pf",
"kcFormCardAccountClass": "login-pf-accounts",
"kcFormSocialAccountClass": "login-pf-social-section",
"kcFormSocialAccountContentClass": "col-xs-12 col-sm-6",
"kcFormHeaderClass": "login-pf-header",
"kcFeedbackErrorIcon": "pficon pficon-error-circle-o",
"kcFeedbackWarningIcon": "pficon pficon-warning-triangle-o",
"kcFeedbackSuccessIcon": "pficon pficon-ok",
"kcFeedbackInfoIcon": "pficon pficon-info",
"kcResetFlowIcon": "pficon pficon-arrow fa-2x",
"kcFormGroupClass": "form-group",
"kcLabelWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
"kcSignUpClass": "login-pf-sighup"
};
/** Tu use if you don't want any default */
export const allClearKcTemplateProperties =
allPropertiesValuesToUndefined(defaultKcTemplateProperties);
export type KcPagesProperties = KcClasses<
KcTemplateCssClasses |
"kcLogoLink" |
"kcLogoClass" |
"kcContainerClass" |
"kcContentClass" |
"kcFeedbackAreaClass" |
"kcLocaleClass" |
"kcAlertIconClasserror" |
"kcFormAreaClass" |
"kcFormSocialAccountListClass" |
"kcFormSocialAccountDoubleListClass" |
"kcFormSocialAccountListLinkClass" |
"kcWebAuthnKeyIcon" |
"kcFormClass" |
"kcFormGroupErrorClass" |
"kcLabelClass" |
"kcInputClass" |
"kcInputWrapperClass" |
"kcFormOptionsClass" |
"kcFormButtonsClass" |
"kcFormSettingClass" |
"kcTextareaClass" |
"kcInfoAreaClass" |
"kcButtonClass" |
"kcButtonPrimaryClass" |
"kcButtonDefaultClass" |
"kcButtonLargeClass" |
"kcButtonBlockClass" |
"kcInputLargeClass" |
"kcSrOnlyClass" |
"kcSelectAuthListClass" |
"kcSelectAuthListItemClass" |
"kcSelectAuthListItemInfoClass" |
"kcSelectAuthListItemLeftClass" |
"kcSelectAuthListItemBodyClass" |
"kcSelectAuthListItemDescriptionClass" |
"kcSelectAuthListItemHeadingClass" |
"kcSelectAuthListItemHelpTextClass" |
"kcAuthenticatorDefaultClass" |
"kcAuthenticatorPasswordClass" |
"kcAuthenticatorOTPClass" |
"kcAuthenticatorWebAuthnClass" |
"kcAuthenticatorWebAuthnPasswordlessClass" |
"kcSelectOTPListClass" |
"kcSelectOTPListItemClass" |
"kcAuthenticatorOtpCircleClass" |
"kcSelectOTPItemHeadingClass" |
"kcFormOptionsWrapperClass"
>;
export const defaultKcPagesProperties: KcPagesProperties = {
...defaultKcTemplateProperties,
"kcLogoLink": "http://www.keycloak.org",
"kcLogoClass": "login-pf-brand",
"kcContainerClass": "container-fluid",
"kcContentClass": "col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3",
"kcFeedbackAreaClass": "col-md-12",
"kcLocaleClass": "col-xs-12 col-sm-1",
"kcAlertIconClasserror": "pficon pficon-error-circle-o",
"kcFormAreaClass": "col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2",
"kcFormSocialAccountListClass": "login-pf-social list-unstyled login-pf-social-all",
"kcFormSocialAccountDoubleListClass": "login-pf-social-double-col",
"kcFormSocialAccountListLinkClass": "login-pf-social-link",
"kcWebAuthnKeyIcon": "pficon pficon-key",
"kcFormClass": "form-horizontal",
"kcFormGroupErrorClass": "has-error",
"kcLabelClass": "control-label",
"kcInputClass": "form-control",
"kcInputWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
"kcFormOptionsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
"kcFormButtonsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
"kcFormSettingClass": "login-pf-settings",
"kcTextareaClass": "form-control",
"kcInfoAreaClass": "col-xs-12 col-sm-4 col-md-4 col-lg-5 details",
// css classes for form buttons main class used for all buttons
"kcButtonClass": "btn",
// classes defining priority of the button - primary or default (there is typically only one priority button for the form)
"kcButtonPrimaryClass": "btn-primary",
"kcButtonDefaultClass": "btn-default",
// classes defining size of the button
"kcButtonLargeClass": "btn-lg",
"kcButtonBlockClass": "btn-block",
// css classes for input
"kcInputLargeClass": "input-lg",
// css classes for form accessability
"kcSrOnlyClass": "sr-only",
// css classes for select-authenticator form
"kcSelectAuthListClass": "list-group list-view-pf",
"kcSelectAuthListItemClass": "list-group-item list-view-pf-stacked",
"kcSelectAuthListItemInfoClass": "list-view-pf-main-info",
"kcSelectAuthListItemLeftClass": "list-view-pf-left",
"kcSelectAuthListItemBodyClass": "list-view-pf-body",
"kcSelectAuthListItemDescriptionClass": "list-view-pf-description",
"kcSelectAuthListItemHeadingClass": "list-group-item-heading",
"kcSelectAuthListItemHelpTextClass": "list-group-item-text",
// css classes for the authenticators
"kcAuthenticatorDefaultClass": "fa list-view-pf-icon-lg",
"kcAuthenticatorPasswordClass": "fa fa-unlock list-view-pf-icon-lg",
"kcAuthenticatorOTPClass": "fa fa-mobile list-view-pf-icon-lg",
"kcAuthenticatorWebAuthnClass": "fa fa-key list-view-pf-icon-lg",
"kcAuthenticatorWebAuthnPasswordlessClass": "fa fa-key list-view-pf-icon-lg",
//css classes for the OTP Login Form
"kcSelectOTPListClass": "card-pf card-pf-view card-pf-view-select card-pf-view-single-select",
"kcSelectOTPListItemClass": "card-pf-body card-pf-top-element",
"kcAuthenticatorOtpCircleClass": "fa fa-mobile card-pf-icon-circle",
"kcSelectOTPItemHeadingClass": "card-pf-title text-center"
};
/** Tu use if you don't want any default */
export const allClearKcLoginPageProperties =
allPropertiesValuesToUndefined(defaultKcPagesProperties);

View File

@ -0,0 +1,205 @@
import { allPropertiesValuesToUndefined } from "../tools/allPropertiesValuesToUndefined";
import { doExtends } from "evt/tools/typeSafety/doExtends";
/** Class names can be provided as an array or separated by whitespace */
export type KcPropsGeneric<CssClasses extends string> = { [key in CssClasses]: readonly string[] | string | undefined; };
export type KcTemplateClassKey =
"stylesCommon" |
"styles" |
"scripts" |
"kcHtmlClass" |
"kcLoginClass" |
"kcHeaderClass" |
"kcHeaderWrapperClass" |
"kcFormCardClass" |
"kcFormCardAccountClass" |
"kcFormHeaderClass" |
"kcLocaleWrapperClass" |
"kcContentWrapperClass" |
"kcLabelWrapperClass" |
"kcContentWrapperClass" |
"kcLabelWrapperClass" |
"kcFormGroupClass" |
"kcResetFlowIcon" |
"kcResetFlowIcon" |
"kcFeedbackSuccessIcon" |
"kcFeedbackWarningIcon" |
"kcFeedbackErrorIcon" |
"kcFeedbackInfoIcon" |
"kcContentWrapperClass" |
"kcFormSocialAccountContentClass" |
"kcFormSocialAccountClass" |
"kcSignUpClass" |
"kcInfoAreaWrapperClass"
;
export type KcTemplateProps = KcPropsGeneric<KcTemplateClassKey>;
export const defaultKcTemplateProps = {
"stylesCommon": [
"node_modules/patternfly/dist/css/patternfly.min.css",
"node_modules/patternfly/dist/css/patternfly-additions.min.css",
"lib/zocial/zocial.css"
],
"styles": ["css/login.css"],
"scripts": [],
"kcHtmlClass": ["login-pf"],
"kcLoginClass": ["login-pf-page"],
"kcContentWrapperClass": ["row"],
"kcHeaderClass": ["login-pf-page-header"],
"kcHeaderWrapperClass": [],
"kcFormCardClass": ["card-pf"],
"kcFormCardAccountClass": ["login-pf-accounts"],
"kcFormSocialAccountClass": ["login-pf-social-section"],
"kcFormSocialAccountContentClass": ["col-xs-12", "col-sm-6"],
"kcFormHeaderClass": ["login-pf-header"],
"kcLocaleWrapperClass": [],
"kcFeedbackErrorIcon": ["pficon", "pficon-error-circle-o"],
"kcFeedbackWarningIcon": ["pficon", "pficon-warning-triangle-o"],
"kcFeedbackSuccessIcon": ["pficon", "pficon-ok"],
"kcFeedbackInfoIcon": ["pficon", "pficon-info"],
"kcResetFlowIcon": ["pficon", "pficon-arrow fa-2x"],
"kcFormGroupClass": ["form-group"],
"kcLabelWrapperClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcSignUpClass": ["login-pf-signup"],
"kcInfoAreaWrapperClass": []
} as const;
doExtends<typeof defaultKcTemplateProps, KcTemplateProps>();
/** Tu use if you don't want any default */
export const allClearKcTemplateProps =
allPropertiesValuesToUndefined(defaultKcTemplateProps);
doExtends<typeof allClearKcTemplateProps, KcTemplateProps>();
export type KcProps = KcPropsGeneric<
KcTemplateClassKey |
"kcLogoLink" |
"kcLogoClass" |
"kcContainerClass" |
"kcContentClass" |
"kcFeedbackAreaClass" |
"kcLocaleClass" |
"kcAlertIconClasserror" |
"kcFormAreaClass" |
"kcFormSocialAccountListClass" |
"kcFormSocialAccountDoubleListClass" |
"kcFormSocialAccountListLinkClass" |
"kcWebAuthnKeyIcon" |
"kcFormClass" |
"kcFormGroupErrorClass" |
"kcLabelClass" |
"kcInputClass" |
"kcInputWrapperClass" |
"kcFormOptionsClass" |
"kcFormButtonsClass" |
"kcFormSettingClass" |
"kcTextareaClass" |
"kcInfoAreaClass" |
"kcButtonClass" |
"kcButtonPrimaryClass" |
"kcButtonDefaultClass" |
"kcButtonLargeClass" |
"kcButtonBlockClass" |
"kcInputLargeClass" |
"kcSrOnlyClass" |
"kcSelectAuthListClass" |
"kcSelectAuthListItemClass" |
"kcSelectAuthListItemInfoClass" |
"kcSelectAuthListItemLeftClass" |
"kcSelectAuthListItemBodyClass" |
"kcSelectAuthListItemDescriptionClass" |
"kcSelectAuthListItemHeadingClass" |
"kcSelectAuthListItemHelpTextClass" |
"kcAuthenticatorDefaultClass" |
"kcAuthenticatorPasswordClass" |
"kcAuthenticatorOTPClass" |
"kcAuthenticatorWebAuthnClass" |
"kcAuthenticatorWebAuthnPasswordlessClass" |
"kcSelectOTPListClass" |
"kcSelectOTPListItemClass" |
"kcAuthenticatorOtpCircleClass" |
"kcSelectOTPItemHeadingClass" |
"kcFormOptionsWrapperClass"
>;
export const defaultKcProps = {
...defaultKcTemplateProps,
"kcLogoLink": "http://www.keycloak.org",
"kcLogoClass": "login-pf-brand",
"kcContainerClass": "container-fluid",
"kcContentClass": ["col-sm-8", "col-sm-offset-2", "col-md-6", "col-md-offset-3", "col-lg-6", "col-lg-offset-3"],
"kcFeedbackAreaClass": ["col-md-12"],
"kcLocaleClass": ["col-xs-12", "col-sm-1"],
"kcAlertIconClasserror": ["pficon", "pficon-error-circle-o"],
"kcFormAreaClass": ["col-sm-10", "col-sm-offset-1", "col-md-8", "col-md-offset-2", "col-lg-8", "col-lg-offset-2"],
"kcFormSocialAccountListClass": ["login-pf-social", "list-unstyled", "login-pf-social-all"],
"kcFormSocialAccountDoubleListClass": ["login-pf-social-double-col"],
"kcFormSocialAccountListLinkClass": ["login-pf-social-link"],
"kcWebAuthnKeyIcon": ["pficon", "pficon-key"],
"kcFormClass": ["form-horizontal"],
"kcFormGroupErrorClass": ["has-error"],
"kcLabelClass": ["control-label"],
"kcInputClass": ["form-control"],
"kcInputWrapperClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcFormOptionsClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcFormButtonsClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcFormSettingClass": ["login-pf-settings"],
"kcTextareaClass": ["form-control"],
"kcInfoAreaClass": ["col-xs-12", "col-sm-4", "col-md-4", "col-lg-5", "details"],
// css classes for form buttons main class used for all buttons
"kcButtonClass": ["btn"],
// classes defining priority of the button - primary or default (there is typically only one priority button for the form)
"kcButtonPrimaryClass": ["btn-primary"],
"kcButtonDefaultClass": ["btn-default"],
// classes defining size of the button
"kcButtonLargeClass": ["btn-lg"],
"kcButtonBlockClass": ["btn-block"],
// css classes for input
"kcInputLargeClass": ["input-lg"],
// css classes for form accessability
"kcSrOnlyClass": ["sr-only"],
// css classes for select-authenticator form
"kcSelectAuthListClass": ["list-group", "list-view-pf"],
"kcSelectAuthListItemClass": ["list-group-item", "list-view-pf-stacked"],
"kcSelectAuthListItemInfoClass": ["list-view-pf-main-info"],
"kcSelectAuthListItemLeftClass": ["list-view-pf-left"],
"kcSelectAuthListItemBodyClass": ["list-view-pf-body"],
"kcSelectAuthListItemDescriptionClass": ["list-view-pf-description"],
"kcSelectAuthListItemHeadingClass": ["list-group-item-heading"],
"kcSelectAuthListItemHelpTextClass": ["list-group-item-text"],
// css classes for the authenticators
"kcAuthenticatorDefaultClass": ["fa", "list-view-pf-icon-lg"],
"kcAuthenticatorPasswordClass": ["fa", "fa-unlock list-view-pf-icon-lg"],
"kcAuthenticatorOTPClass": ["fa", "fa-mobile", "list-view-pf-icon-lg"],
"kcAuthenticatorWebAuthnClass": ["fa", "fa-key", "list-view-pf-icon-lg"],
"kcAuthenticatorWebAuthnPasswordlessClass": ["fa", "fa-key", "list-view-pf-icon-lg"],
//css classes for the OTP Login Form
"kcSelectOTPListClass": ["card-pf", "card-pf-view", "card-pf-view-select", "card-pf-view-single-select"],
"kcSelectOTPListItemClass": ["card-pf-body", "card-pf-top-element"],
"kcAuthenticatorOtpCircleClass": ["fa", "fa-mobile", "card-pf-icon-circle"],
"kcSelectOTPItemHeadingClass": ["card-pf-title", "text-center"],
"kcFormOptionsWrapperClass": []
} as const;
doExtends<typeof defaultKcProps, KcProps>();
/** Tu use if you don't want any default */
export const allClearKcProps =
allPropertiesValuesToUndefined(defaultKcProps);
doExtends<typeof allClearKcProps, KcProps>();

View File

@ -1,37 +1,21 @@
import { useState, memo } from "react";
import { Template } from "./Template";
import type { KcPagesProperties } from "./KcProperties";
import { defaultKcPagesProperties } from "./KcProperties";
import { assert } from "evt/tools/typeSafety/assert";
import { kcContext } from "../kcContext";
import { useKcTranslation } from "../i18n/useKcTranslation";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
import { cx } from "tss-react";
import { useConstCallback } from "powerhooks";
export type LoginProps = {
kcProperties?: KcPagesProperties;
};
export const Login = memo(({ kcContext, ...props }: { kcContext: KcContext.Login; } & KcProps) => {
export const Login = memo((props: LoginProps) => {
const { msg, msgStr } = useKcMessage();
const { kcProperties = {} } = props;
const { t, tStr } = useKcTranslation();
Object.assign(kcProperties, defaultKcPagesProperties);
const [{
const {
social, realm, url,
usernameEditDisabled, login,
auth, registrationDisabled
}] = useState(() => (
assert(
kcContext !== undefined,
"App is currently being served by keycloak"
),
kcContext
));
} = kcContext;
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
@ -39,57 +23,55 @@ export const Login = memo((props: LoginProps) => {
(setIsLoginButtonDisabled(true), true)
);
return (
<Template
{...{ kcContext, ...props }}
displayInfo={social.displayInfo}
displayWide={realm.password && social.providers !== undefined}
kcProperties={kcProperties}
headerNode={t("doLogIn")}
showUsernameNode={null}
headerNode={msg("doLogIn")}
formNode={
<div
id="kc-form"
className={cx(realm.password && social.providers !== undefined && kcProperties.kcContentWrapperClass)}
className={cx(realm.password && social.providers !== undefined && props.kcContentWrapperClass)}
>
<div
id="kc-form-wrapper"
className={cx(realm.password && social.providers && [kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass])}
className={cx(realm.password && social.providers && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}
>
{
realm.password &&
(
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(kcProperties.kcFormGroupClass)}>
<label htmlFor="username" className={cx(kcProperties.kcLabelClass)}>
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{
!realm.loginWithEmailAllowed ?
t("username")
msg("username")
:
(
!realm.registrationEmailAsUsername ?
t("usernameOrEmail") :
t("email")
msg("usernameOrEmail") :
msg("email")
)
}
</label>
<input
tabIndex={1}
id="username"
className={cx(kcProperties.kcInputClass)}
className={cx(props.kcInputClass)}
name="username"
value={login.username ?? ''}
defaultValue={login.username ?? ''}
type="text"
{...(usernameEditDisabled ? { "disabled": true } : { "autofocus": true, "autocomplete": "off" })}
{...(usernameEditDisabled ? { "disabled": true } : { "autoFocus": true, "autoComplete": "off" })}
/>
</div>
<div className={cx(kcProperties.kcFormGroupClass)}>
<label htmlFor="password" className={cx(kcProperties.kcLabelClass)}>
{t("password")}
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}>
{msg("password")}
</label>
<input tabIndex={2} id="password" className={cx(kcProperties.kcInputClass)} name="password" type="password" autoComplete="off" />
<input tabIndex={2} id="password" className={cx(props.kcInputClass)} name="password" type="password" autoComplete="off" />
</div>
<div className={cx(kcProperties.kcFormGroupClass, kcProperties.kcFormSettingClass)}>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
<div id="kc-form-options">
{
(
@ -98,22 +80,23 @@ export const Login = memo((props: LoginProps) => {
) &&
<div className="checkbox">
<label>
<input tabIndex={3} id="rememberMe" name="rememberMe" type="checkbox" {...(login.rememberMe ? { "checked": true } : {})}> {t("rememberMe")}</input>
<input tabIndex={3} id="rememberMe" name="rememberMe" type="checkbox" {...(login.rememberMe ? { "checked": true } : {})} />
{msg("rememberMe")}
</label>
</div>
}
</div>
<div className={cx(kcProperties.kcFormOptionsWrapperClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
{
realm.resetPasswordAllowed &&
<span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}>{t("doForgotPassword")}</a>
<a tabIndex={5} href={url.loginResetCredentialsUrl}>{msg("doForgotPassword")}</a>
</span>
}
</div>
</div>
<div id="kc-form-buttons" className={cx(kcProperties.kcFormGroupClass)}>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}>
<input
type="hidden"
id="id-hidden-input"
@ -122,8 +105,8 @@ export const Login = memo((props: LoginProps) => {
/>
<input
tabIndex={4}
className={cx(kcProperties.kcButtonClass, kcProperties.kcButtonPrimaryClass, kcProperties.kcButtonBlockClass, kcProperties.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
value={tStr("doLogIn")}
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
value={msgStr("doLogIn")}
disabled={isLoginButtonDisabled}
/>
</div>
@ -133,11 +116,11 @@ export const Login = memo((props: LoginProps) => {
</div>
{
(realm.password && social.providers !== undefined) &&
<div id="kc-social-providers" className={cx(kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass)}>
<ul className={cx(kcProperties.kcFormSocialAccountListClass, social.providers.length > 4 && kcProperties.kcFormSocialAccountDoubleListClass)}>
<div id="kc-social-providers" className={cx(props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass)}>
<ul className={cx(props.kcFormSocialAccountListClass, social.providers.length > 4 && props.kcFormSocialAccountDoubleListClass)}>
{
social.providers.map(p =>
<li className={cx(kcProperties.kcFormSocialAccountListLinkClass)}>
<li className={cx(props.kcFormSocialAccountListLinkClass)}>
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
<span>{p.displayName}</span>
</a>
@ -149,17 +132,17 @@ export const Login = memo((props: LoginProps) => {
}
</div>
}
displayInfoNode={
infoNode={
(
realm.password &&
realm.resetPasswordAllowed &&
realm.registrationAllowed &&
!registrationDisabled
) &&
<div id="kc-registration">
<span>
{t("noAccount")}
{msg("noAccount")}
<a tabIndex={6} href={url.registrationUrl}>
{t("doRegister")}
{msg("doRegister")}
</a>
</span>
</div>

View File

@ -0,0 +1,145 @@
import { useEffect, memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
import { appendHead } from "../tools/appendHead";
import { join as pathJoin } from "path";
import { cx } from "tss-react";
export const LoginOtp = memo(({ kcContext, ...props }: { kcContext: KcContext.LoginOtp; } & KcProps) => {
const { otpLogin, url } = kcContext;
const { msg, msgStr } = useKcMessage();
useEffect(
() => {
let isCleanedUp = false;
appendHead({
"type": "javascript",
"src": pathJoin(
kcContext.url.resourcesCommonPath,
"node_modules/jquery/dist/jquery.min.js"
)
}).then(() => {
if (isCleanedUp) return;
evaluateInlineScript();
});
return () => { isCleanedUp = true };
},
[]
);
return (
<Template
{...{ kcContext, ...props }}
headerNode={msg("doLogIn")}
formNode={
<form
id="kc-otp-login-form"
className={cx(props.kcFormClass)}
action={url.loginAction}
method="post"
>
{
otpLogin.userOtpCredentials.length > 1 &&
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcInputWrapperClass)}>
{
otpLogin.userOtpCredentials.map(otpCredential =>
<div key={otpCredential.id} className={cx(props.kcSelectOTPListClass)}>
<input type="hidden" value="${otpCredential.id}" />
<div className={cx(props.kcSelectOTPListItemClass)}>
<span className={cx(props.kcAuthenticatorOtpCircleClass)} />
<h2 className={cx(props.kcSelectOTPItemHeadingClass)}>
{otpCredential.userLabel}
</h2>
</div>
</div>
)
}
</div>
</div>
}
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="otp" className={cx(props.kcLabelClass)}>
{msg("loginOtpOneTime")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
id="otp"
name="otp"
autoComplete="off"
type="text"
className={cx(props.kcInputClass)}
autoFocus
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} />
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass
)}
name="login"
id="kc-login"
type="submit"
value={msgStr("doLogIn")}
/>
</div>
</div>
</form >
}
/>
);
});
declare const $: any;
function evaluateInlineScript() {
$(document).ready(function () {
// Card Single Select
$('.card-pf-view-single-select').click(function (this: any) {
if ($(this).hasClass('active')) { $(this).removeClass('active'); $(this).children().removeAttr('name'); }
else {
$('.card-pf-view-single-select').removeClass('active');
$('.card-pf-view-single-select').children().removeAttr('name');
$(this).addClass('active'); $(this).children().attr('name', 'selectedCredentialId');
}
});
var defaultCred = $('.card-pf-view-single-select')[0];
if (defaultCred) {
defaultCred.click();
}
});
}

View File

@ -0,0 +1,80 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
import { cx } from "tss-react";
export const LoginResetPassword = memo(({ kcContext, ...props }: { kcContext: KcContext.LoginResetPassword; } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const {
url,
realm,
auth
} = kcContext;
return (
<Template
{...{ kcContext, ...props }}
displayMessage={false}
headerNode={msg("emailForgotTitle")}
formNode={
<form id="kc-reset-password-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{
!realm.loginWithEmailAllowed ?
msg("username")
:
!realm.registrationEmailAsUsername ?
msg("usernameOrEmail") :
msg("email")
}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
name="username"
className={cx(props.kcInputClass)}
autoFocus
defaultValue={
auth !== undefined && auth.showUsername ?
auth.attemptedUsername : undefined
}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(
props.kcButtonClass, props.kcButtonPrimaryClass,
props.kcButtonBlockClass, props.kcButtonLargeClass
)}
type="submit"
value={msgStr("doSubmit")}
/>
</div>
</div>
</form>
}
infoNode={msg("emailInstruction")}
/>
);
});

View File

@ -0,0 +1,38 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
export const LoginVerifyEmail = memo(({ kcContext, ...props }: { kcContext: KcContext.LoginVerifyEmail; } & KcProps) => {
const { msg } = useKcMessage();
const {
url
} = kcContext;
return (
<Template
{...{ kcContext, ...props }}
displayMessage={false}
headerNode={msg("emailVerifyTitle")}
formNode={
<>
<p className="instruction">
{msg("emailVerifyInstruction1")}
</p>
<p className="instruction">
{msg("emailVerifyInstruction2")}
<a href={url.loginAction}>{msg("doClickHere")}</a>
{msg("emailVerifyInstruction3")}
</p>
</>
}
/>
);
});

View File

@ -0,0 +1,123 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
import { cx } from "tss-react";
export const Register = memo(({ kcContext, ...props }: { kcContext: KcContext.Register; } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const {
url,
messagesPerField,
register,
realm,
passwordRequired,
recaptchaRequired,
recaptchaSiteKey
} = kcContext;
return (
<Template
{...{ kcContext, ...props }}
headerNode={msg("registerTitle")}
formNode={
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists('firstName', props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(props.kcLabelClass)}>{msg("firstName")}</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="firstName" className={cx(props.kcInputClass)} name="firstName"
defaultValue={register.formData.firstName ?? ""}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(props.kcLabelClass)}>{msg("lastName")}</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="lastName" className={cx(props.kcInputClass)} name="lastName"
defaultValue={register.formData.lastName ?? ""}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists('email', props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(props.kcLabelClass)}>{msg("email")}</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="email" className={cx(props.kcInputClass)} name="email"
defaultValue={register.formData.email ?? ""} autoComplete="email"
/>
</div>
</div>
{
!realm.registrationEmailAsUsername &&
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists('username', props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>{msg("username")}</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="username" className={cx(props.kcInputClass)} name="username"
defaultValue={register.formData.username ?? ""} autoComplete="username" />
</div>
</div >
}
{
passwordRequired &&
<>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}>{msg("password")}</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="password" id="password" className={cx(props.kcInputClass)} name="password" autoComplete="new-password" />
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={cx(props.kcLabelClass)}>{msg("passwordConfirm")}</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="password" id="password-confirm" className={cx(props.kcInputClass)} name="password-confirm" />
</div>
</div>
</>
}
{
recaptchaRequired &&
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
</div>
</div>
}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span><a href={url.loginUrl}>{msg("backToLogin")}</a></span>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} type="submit"
value={msgStr("doRegister")} />
</div>
</div>
</form >
}
/>
);
});

View File

@ -1,33 +1,31 @@
import { useState, useReducer ,useEffect, memo } from "react";
import { useReducer, useEffect, memo } from "react";
import type { ReactNode } from "react";
import { useKcTranslation } from "../i18n/useKcTranslation";
import { kcContext } from "../kcContext";
import { assert } from "evt/tools/typeSafety/assert";
import { cx } from "tss-react";
import { useKcMessage } from "../i18n/useKcMessage";
import { useKcLanguageTag } from "../i18n/useKcLanguageTag";
import type { KcContext } from "../KcContext";
import { assert } from "../tools/assert";
import { cx } from "tss-react";
import type { KcLanguageTag } from "../i18n/KcLanguageTag";
import { getBestMatchAmongKcLanguageTag } from "../i18n/KcLanguageTag";
import { getKcLanguageTagLabel } from "../i18n/KcLanguageTag";
import { useCallbackFactory } from "powerhooks";
import { appendHead } from "../tools/appendHead";
import { join as pathJoin } from "path";
import { useConstCallback } from "powerhooks";
import type { KcTemplateProperties } from "./KcProperties";
import { defaultKcTemplateProperties } from "./KcProperties";
import type { KcTemplateProps } from "./KcProps";
export type TemplateProps = {
kcProperties: KcTemplateProperties;
displayInfo?: boolean;
displayMessage?: boolean;
displayRequiredFields?: boolean;
displayWide?: boolean;
showAnotherWayIfPresent?: boolean;
headerNode: ReactNode;
showUsernameNode: ReactNode;
showUsernameNode?: ReactNode;
formNode: ReactNode;
displayInfoNode: ReactNode;
};
infoNode?: ReactNode;
} & { kcContext: KcContext; } & KcTemplateProps;
export const Template = memo((props: TemplateProps) => {
@ -37,47 +35,65 @@ export const Template = memo((props: TemplateProps) => {
displayRequiredFields = false,
displayWide = false,
showAnotherWayIfPresent = true,
kcProperties = {},
headerNode,
showUsernameNode,
showUsernameNode = null,
formNode,
displayInfoNode
infoNode = null,
kcContext
} = props;
const { t } = useKcTranslation();
useEffect(() => { console.log("Rendering this page with react using keycloakify") }, []);
Object.assign(kcProperties, defaultKcTemplateProperties);
const { msg } = useKcMessage();
const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
const onChangeLanguageClickFactory = useCallbackFactory(
([languageTag]: [KcLanguageTag]) =>
setKcLanguageTag(languageTag)
);
const onTryAnotherWayClick = useConstCallback(() => {
const onTryAnotherWayClick = useConstCallback(() =>
(document.forms["kc-select-try-another-way-form" as never].submit(), false)
);
document.forms["kc-select-try-another-way-form" as never].submit();
const {
realm, locale, auth,
url, message, isAppInitiatedAction
} = kcContext;
return false;
useEffect(() => {
});
if (!realm.internationalizationEnabled) {
return;
}
const [{ realm, locale, auth, url, message, isAppInitiatedAction }] = useState(() => (
assert(kcContext !== undefined, "App is not currently being served by KeyCloak"),
kcContext
));
assert(locale !== undefined);
if (kcLanguageTag === getBestMatchAmongKcLanguageTag(locale.current)) {
return;
}
window.location.href =
locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
}, [kcLanguageTag]);
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
useEffect(() => {
let isUnmounted = false;
const cleanups: (() => void)[] = [];
const toArr = (x: string | readonly string[] | undefined) =>
typeof x === "string" ? x.split(" ") : x ?? [];
Promise.all(
[
...(kcProperties.stylesCommon ?? []).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...(kcProperties.styles ?? []).map(relativePath => pathJoin(url.resourcesPath, relativePath))
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath))
].map(href => appendHead({
"type": "css",
href
@ -91,36 +107,52 @@ export const Template = memo((props: TemplateProps) => {
});
kcProperties.scripts?.forEach(
toArr(props.scripts).forEach(
relativePath => appendHead({
"type": "javascript",
"src": pathJoin(url.resourcesPath, relativePath)
})
);
document.getElementsByTagName("html")[0]
.classList
.add(cx(kcProperties.kcHtmlClass));
if (props.kcHtmlClass !== undefined) {
return () => { isUnmounted = true; };
const htmlClassList =
document.getElementsByTagName("html")[0]
.classList;
}, []);
const tokens = cx(props.kcHtmlClass).split(" ")
htmlClassList.add(...tokens);
cleanups.push(() => htmlClassList.remove(...tokens));
}
return () => {
isUnmounted = true;
cleanups.forEach(f => f());
};
}, [props.kcHtmlClass]);
if (!isExtraCssLoaded) {
return null;
}
return (
<div className={cx(kcProperties.kcLoginClass)}>
<div className={cx(props.kcLoginClass)}>
<div id="kc-header" className={cx(kcProperties.kcHeaderClass)}>
<div id="kc-header-wrapper" className={cx(kcProperties.kcHeaderWrapperClass)}>
{t("loginTitleHtml", realm.displayNameHtml)}
<div id="kc-header" className={cx(props.kcHeaderClass)}>
<div id="kc-header-wrapper" className={cx(props.kcHeaderWrapperClass)}>
{msg("loginTitleHtml", realm.displayNameHtml)}
</div>
</div>
<div className={cx(kcProperties.kcFormCardClass, displayWide && kcProperties.kcFormCardAccountClass)}>
<header className={cx(kcProperties.kcFormHeaderClass)}>
<div className={cx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
<header className={cx(props.kcFormHeaderClass)}>
{
(
realm.internationalizationEnabled &&
@ -128,7 +160,7 @@ export const Template = memo((props: TemplateProps) => {
locale.supported.length > 1
) &&
<div id="kc-locale">
<div id="kc-locale-wrapper" className={cx(kcProperties.kcLocaleWrapperClass)}>
<div id="kc-locale-wrapper" className={cx(props.kcLocaleWrapperClass)}>
<div className="kc-dropdown" id="kc-locale-dropdown">
<a href="#" id="kc-current-locale-link">
{getKcLanguageTagLabel(kcLanguageTag)}
@ -137,14 +169,13 @@ export const Template = memo((props: TemplateProps) => {
{
locale.supported.map(
({ languageTag }) =>
<li className="kc-dropdown-item">
<li key={languageTag} className="kc-dropdown-item">
<a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
{getKcLanguageTagLabel(languageTag)}
</a>
</li>
)
}
</ul>
</div>
@ -162,11 +193,11 @@ export const Template = memo((props: TemplateProps) => {
displayRequiredFields ?
(
<div className={cx(kcProperties.kcContentWrapperClass)}>
<div className={cx(kcProperties.kcLabelWrapperClass, "subtitle")}>
<div className={cx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle">
<span className="required">*</span>
{t("requiredFields")}
{msg("requiredFields")}
</span>
</div>
<div className="col-md-10">
@ -183,19 +214,19 @@ export const Template = memo((props: TemplateProps) => {
)
) : (
displayRequiredFields ? (
<div className={cx(kcProperties.kcContentWrapperClass)}>
<div className={cx(kcProperties.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle"><span className="required">*</span> {t("requiredFields")}</span>
<div className={cx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle"><span className="required">*</span> {msg("requiredFields")}</span>
</div>
<div className="col-md-10">
{showUsernameNode}
<div className={cx(kcProperties.kcFormGroupClass)}>
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(kcProperties.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
@ -203,21 +234,21 @@ export const Template = memo((props: TemplateProps) => {
</div>
</div>
) : (
<>
{showUsernameNode}
<div className={cx(kcProperties.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(kcProperties.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
</div>
</a>
</div>
<>
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
</>
)
</div>
</>
)
)
}
</header>
@ -234,10 +265,10 @@ export const Template = memo((props: TemplateProps) => {
)
) &&
<div className={cx("alert", `alert-${message.type}`)}>
{message.type === "success" && <span className={cx(kcProperties.kcFeedbackSuccessIcon)}></span>}
{message.type === "warning" && <span className={cx(kcProperties.kcFeedbackWarningIcon)}></span>}
{message.type === "error" && <span className={cx(kcProperties.kcFeedbackErrorIcon)}></span>}
{message.type === "info" && <span className={cx(kcProperties.kcFeedbackInfoIcon)}></span>}
{message.type === "success" && <span className={cx(props.kcFeedbackSuccessIcon)}></span>}
{message.type === "warning" && <span className={cx(props.kcFeedbackWarningIcon)}></span>}
{message.type === "error" && <span className={cx(props.kcFeedbackErrorIcon)}></span>}
{message.type === "info" && <span className={cx(props.kcFeedbackInfoIcon)}></span>}
<span className="kc-feedback-text">{message.summary}</span>
</div>
}
@ -249,11 +280,11 @@ export const Template = memo((props: TemplateProps) => {
showAnotherWayIfPresent
) &&
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post" className={cx(displayWide && kcProperties.kcContentWrapperClass)} >
<div className={cx(displayWide && [kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass])} >
<div className={cx(kcProperties.kcFormGroupClass)}>
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post" className={cx(displayWide && props.kcContentWrapperClass)} >
<div className={cx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])} >
<div className={cx(props.kcFormGroupClass)}>
<input type="hidden" name="tryAnotherWay" value="on" />
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>{t("doTryAnotherWay")}</a>
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>{msg("doTryAnotherWay")}</a>
</div>
</div >
</form>
@ -261,9 +292,9 @@ export const Template = memo((props: TemplateProps) => {
{
displayInfo &&
<div id="kc-info" className={cx(kcProperties.kcSignUpClass)}>
<div id="kc-info-wrapper" className={cx(kcProperties.kcInfoAreaWrapperClass)}>
{displayInfoNode}
<div id="kc-info" className={cx(props.kcSignUpClass)}>
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}>
{infoNode}
</div>
</div>
}

View File

@ -0,0 +1,57 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
import { cx } from "tss-react";
export const Terms = memo(({ kcContext, ...props }: { kcContext: KcContext.Terms; } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const { url } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
displayMessage={false}
headerNode={msg("termsTitle")}
formNode={
<>
<div id="kc-terms-text">
{msg("termsText")}
</div>
<form className="form-actions" action={url.loginAction} method="POST">
<input
className={cx(
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonLargeClass
)}
name="accept"
id="kc-accept"
type="submit"
value={msgStr("doAccept")}
/>
<input
className={cx(
props.kcButtonClass,
props.kcButtonDefaultClass,
props.kcButtonLargeClass
)}
name="cancel"
id="kc-decline"
type="submit"
value={msgStr("doDecline")}
/>
</form>
<div className="clearfix" />
</>
}
/>
);
});

View File

@ -1,14 +1,14 @@
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
import { messages } from "./generated_messages/login";
import { kcMessages } from "./kcMessages/login";
export type KcLanguageTag = keyof typeof messages;
export type KcLanguageTag = keyof typeof kcMessages;
export type LanguageLabel =
/* spell-checker: disable */
"Deutsch" | "Norsk" | "Русский" | "Svenska" | "Português (Brasil)" | "Lietuvių" |
"English" | "Italiano" | "Français" | "中文简体" | "Español" | "Čeština" | "日本語" |
"Slovenčina" | "Polish" | "Català" | "Nederlands" | "tr";
"Slovenčina" | "Polski" | "Català" | "Nederlands" | "Türkçe";
/* spell-checker: enable */
export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
@ -24,16 +24,15 @@ export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
case "no": return "Norsk";
case "pt-BR": return "Português (Brasil)";
case "ru": return "Русский";
case "sk":
case "sv": return "Slovenčina";
case "sk": return "Slovenčina";
case "ja": return "日本語";
case "pl": return "Polish";
case "pl": return "Polski";
case "zh-CN": return "中文简体"
case "sv": return "Svenska";
case "lt": return "Lietuvių";
case "cs": return "Čeština";
case "nl": return "Nederlands";
case "tr": return "tr"
case "tr": return "Türkçe";
/* spell-checker: enable */
}
@ -41,7 +40,7 @@ export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
}
const availableLanguages = objectKeys(messages);
const availableLanguages = objectKeys(kcMessages);
/**
* Pass in "fr-FR" or "français" for example, it will return the AvailableLanguage
@ -55,12 +54,16 @@ export function getBestMatchAmongKcLanguageTag(
const iso2LanguageLike = languageLike.split("-")[0].toLowerCase();
const language = availableLanguages.find(language =>
const kcLanguageTag = availableLanguages.find(language =>
language.toLowerCase().includes(iso2LanguageLike) ||
getKcLanguageTagLabel(language).toLocaleLowerCase() === languageLike.toLocaleLowerCase()
);
if (language === undefined && languageLike !== navigator.language) {
if (kcLanguageTag !== undefined) {
return kcLanguageTag;
}
if (languageLike !== navigator.language) {
return getBestMatchAmongKcLanguageTag(navigator.language);
}

View File

@ -2,7 +2,7 @@
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const messages= {
export const kcMessages= {
"ca": {
"doSave": "Desa",
"doCancel": "Cancel·la",
@ -18,7 +18,7 @@ export const messages= {
"accountManagementTitle": "Gestió de Compte Keycloak",
"authenticatorTitle": "Autenticador",
"applicationsHtmlTitle": "Aplicacions",
"authenticatorCode": "Codi d''un sol ús",
"authenticatorCode": "Codi d'un sol ús",
"email": "Email",
"firstName": "Nom",
"givenName": "Nom de pila",
@ -45,11 +45,11 @@ export const messages= {
"role_view-applications": "Veure aplicacions",
"role_view-clients": "Veure clients",
"role_view-events": "Veure events",
"role_view-identity-providers": "Veure proveïdors d''identitat",
"role_view-identity-providers": "Veure proveïdors d'identitat",
"role_manage-realm": "Gestionar domini",
"role_manage-users": "Gestinar usuaris",
"role_manage-applications": "Gestionar aplicacions",
"role_manage-identity-providers": "Gestionar proveïdors d''identitat",
"role_manage-identity-providers": "Gestionar proveïdors d'identitat",
"role_manage-clients": "Gestionar clients",
"role_manage-events": "Gestionar events",
"role_view-profile": "Veure perfil",
@ -57,12 +57,12 @@ export const messages= {
"role_read-token": "Llegir token",
"role_offline-access": "Accés sense connexió",
"client_account": "Compte",
"client_security-admin-console": "Consola d''Administració de Seguretat",
"client_security-admin-console": "Consola d'Administració de Seguretat",
"client_realm-management": "Gestió de domini",
"client_broker": "Broker",
"requiredFields": "Camps obligatoris",
"allFieldsRequired": "Tots els camps obligatoris",
"backToApplication": "&laquo; Torna a l''aplicació",
"backToApplication": "&laquo; Torna a l'aplicació",
"backTo": "Torna a {0}",
"date": "Data",
"event": "Event",
@ -87,49 +87,49 @@ export const messages= {
"action": "Acció",
"inResource": "a",
"fullAccess": "Accés total",
"offlineToken": "Codi d''autorització offline",
"offlineToken": "Codi d'autorització offline",
"revoke": "Revocar permís",
"configureAuthenticators": "Autenticadors configurats",
"mobile": "Mòbil",
"totpStep1": "Instal·la <a href=\"https://freeotp.github.io/\" target=\"_blank\">FreeOTP</a> o Google Authenticator al teu telèfon mòbil. Les dues aplicacions estan disponibles a <a href=\"https://play.google.com\">Google Play</a> i en l''App Store d''Apple.",
"totpStep2": "Obre l''aplicació i escaneja el codi o introdueix la clau.",
"totpStep3": "Introdueix el codi únic que et mostra l''aplicació d''autenticació i fes clic a Envia per finalitzar la configuració",
"totpStep1": "Instal·la <a href=\"https://freeotp.github.io/\" target=\"_blank\">FreeOTP</a> o Google Authenticator al teu telèfon mòbil. Les dues aplicacions estan disponibles a <a href=\"https://play.google.com\">Google Play</a> i en l'App Store d'Apple.",
"totpStep2": "Obre l'aplicació i escaneja el codi o introdueix la clau.",
"totpStep3": "Introdueix el codi únic que et mostra l'aplicació d'autenticació i fes clic a Envia per finalitzar la configuració",
"missingUsernameMessage": "Si us plau indica el teu usuari.",
"missingFirstNameMessage": "Si us plau indica el nom.",
"invalidEmailMessage": "Email no vàlid",
"missingLastNameMessage": "Si us plau indica els teus cognoms.",
"missingEmailMessage": "Si us plau indica l''email.",
"missingEmailMessage": "Si us plau indica l'email.",
"missingPasswordMessage": "Si us plau indica la contrasenya.",
"notMatchPasswordMessage": "Les contrasenyes no coincideixen.",
"missingTotpMessage": "Si us plau indica el teu codi d''autenticació",
"missingTotpMessage": "Si us plau indica el teu codi d'autenticació",
"invalidPasswordExistingMessage": "La contrasenya actual no és correcta.",
"invalidPasswordConfirmMessage": "La confirmació de contrasenya no coincideix.",
"invalidTotpMessage": "El código de autenticación no es válido.",
"usernameExistsMessage": "L''usuari ja existeix",
"emailExistsMessage": "L''email ja existeix",
"usernameExistsMessage": "L'usuari ja existeix",
"emailExistsMessage": "L'email ja existeix",
"readOnlyUserMessage": "No pots actualitzar el teu usuari perquè el teu compte és de només lectura.",
"readOnlyPasswordMessage": "No pots actualitzar la contrasenya perquè el teu compte és de només lectura.",
"successTotpMessage": "Aplicació d''autenticació mòbil configurada.",
"successTotpRemovedMessage": "Aplicació d''autenticació mòbil eliminada.",
"successTotpMessage": "Aplicació d'autenticació mòbil configurada.",
"successTotpRemovedMessage": "Aplicació d'autenticació mòbil eliminada.",
"successGrantRevokedMessage": "Permís revocat correctament",
"accountUpdatedMessage": "El teu compte s''ha actualitzat.",
"accountPasswordUpdatedMessage": "La contrasenya s''ha actualitzat.",
"missingIdentityProviderMessage": "Proveïdor d''identitat no indicat.",
"accountUpdatedMessage": "El teu compte s'ha actualitzat.",
"accountPasswordUpdatedMessage": "La contrasenya s'ha actualitzat.",
"missingIdentityProviderMessage": "Proveïdor d'identitat no indicat.",
"invalidFederatedIdentityActionMessage": "Acció no vàlida o no indicada.",
"identityProviderNotFoundMessage": "No s''ha trobat un proveïdor d''identitat.",
"identityProviderNotFoundMessage": "No s'ha trobat un proveïdor d'identitat.",
"federatedIdentityLinkNotActiveMessage": "Aquesta identitat ja no està activa",
"federatedIdentityRemovingLastProviderMessage": "No pots eliminar l''última identitat federada perquè no tens fixada una contrasenya.",
"identityProviderRedirectErrorMessage": "Error en la redirecció al proveïdor d''identitat",
"identityProviderRemovedMessage": "Proveïdor d''identitat esborrat correctament.",
"accountDisabledMessage": "El compte està desactivada, contacteu amb l''administrador.",
"accountTemporarilyDisabledMessage": "El compte està temporalment desactivat, contacta amb l''administrador o intenta-ho de nou més tard.",
"federatedIdentityRemovingLastProviderMessage": "No pots eliminar l'última identitat federada perquè no tens fixada una contrasenya.",
"identityProviderRedirectErrorMessage": "Error en la redirecció al proveïdor d'identitat",
"identityProviderRemovedMessage": "Proveïdor d'identitat esborrat correctament.",
"accountDisabledMessage": "El compte està desactivada, contacteu amb l'administrador.",
"accountTemporarilyDisabledMessage": "El compte està temporalment desactivat, contacta amb l'administrador o intenta-ho de nou més tard.",
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mínima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d''usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l''expressió regular.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressió regular.",
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes."
},
"cs": {
@ -571,18 +571,18 @@ export const messages= {
"missingLastNameMessage": "Please specify last name.",
"missingEmailMessage": "Please specify email.",
"missingPasswordMessage": "Please specify password.",
"notMatchPasswordMessage": "Passwords don''t match.",
"notMatchPasswordMessage": "Passwords don't match.",
"invalidUserMessage": "Invalid user",
"missingTotpMessage": "Please specify authenticator code.",
"missingTotpDeviceNameMessage": "Please specify device name.",
"invalidPasswordExistingMessage": "Invalid existing password.",
"invalidPasswordConfirmMessage": "Password confirmation doesn''t match.",
"invalidPasswordConfirmMessage": "Password confirmation doesn't match.",
"invalidTotpMessage": "Invalid authenticator code.",
"usernameExistsMessage": "Username already exists.",
"emailExistsMessage": "Email already exists.",
"readOnlyUserMessage": "You can''t update your account as it is read-only.",
"readOnlyUsernameMessage": "You can''t update your username as it is read-only.",
"readOnlyPasswordMessage": "You can''t update your password as your account is read-only.",
"readOnlyUserMessage": "You can't update your account as it is read-only.",
"readOnlyUsernameMessage": "You can't update your username as it is read-only.",
"readOnlyPasswordMessage": "You can't update your password as your account is read-only.",
"successTotpMessage": "Mobile authenticator configured.",
"successTotpRemovedMessage": "Mobile authenticator removed.",
"successGrantRevokedMessage": "Grant revoked successfully.",
@ -592,7 +592,7 @@ export const messages= {
"invalidFederatedIdentityActionMessage": "Invalid or missing action.",
"identityProviderNotFoundMessage": "Specified identity provider not found.",
"federatedIdentityLinkNotActiveMessage": "This identity is not active anymore.",
"federatedIdentityRemovingLastProviderMessage": "You can''t remove last federated identity as you don''t have a password.",
"federatedIdentityRemovingLastProviderMessage": "You can't remove last federated identity as you don't have a password.",
"identityProviderRedirectErrorMessage": "Failed to redirect to identity provider.",
"identityProviderRemovedMessage": "Identity provider removed successfully.",
"identityProviderAlreadyLinkedMessage": "Federated identity returned by {0} is already linked to another user.",
@ -609,7 +609,7 @@ export const messages= {
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
"invalidPasswordGenericMessage": "Invalid password: new password doesn''t match password policies.",
"invalidPasswordGenericMessage": "Invalid password: new password doesn't match password policies.",
"myResources": "My Resources",
"myResourcesSub": "My resources",
"doDeny": "Deny",
@ -915,25 +915,25 @@ export const messages= {
"role_view-applications": "Voir les applications",
"role_view-clients": "Voir les clients",
"role_view-events": "Voir les événements",
"role_view-identity-providers": "Voir les fournisseurs d''identités",
"role_view-identity-providers": "Voir les fournisseurs d'identités",
"role_manage-realm": "Gérer le domaine",
"role_manage-users": "Gérer les utilisateurs",
"role_manage-applications": "Gérer les applications",
"role_manage-identity-providers": "Gérer les fournisseurs d''identités",
"role_manage-identity-providers": "Gérer les fournisseurs d'identités",
"role_manage-clients": "Gérer les clients",
"role_manage-events": "Gérer les événements",
"role_view-profile": "Voir le profil",
"role_manage-account": "Gérer le compte",
"role_read-token": "Lire le jeton d''authentification",
"role_read-token": "Lire le jeton d'authentification",
"role_offline-access": "Accès hors-ligne",
"client_account": "Compte",
"client_security-admin-console": "Console d''administration de la sécurité",
"client_security-admin-console": "Console d'administration de la sécurité",
"client_admin-cli": "Admin CLI",
"client_realm-management": "Gestion du domaine",
"client_broker": "Broker",
"requiredFields": "Champs obligatoires",
"allFieldsRequired": "Tous les champs sont obligatoires",
"backToApplication": "&laquo; Revenir à l''application",
"backToApplication": "&laquo; Revenir à l'application",
"backTo": "Revenir à {0}",
"date": "Date",
"event": "Evénement",
@ -958,15 +958,15 @@ export const messages= {
"action": "Action",
"inResource": "dans",
"fullAccess": "Accès complet",
"offlineToken": "Jeton d''authentification hors-ligne",
"offlineToken": "Jeton d'authentification hors-ligne",
"revoke": "Révoquer un droit",
"configureAuthenticators": "Authentifications configurées.",
"mobile": "Téléphone mobile",
"totpStep1": "Installez une des applications suivantes sur votre mobile",
"totpStep2": "Ouvrez l''application et scannez le code-barres ou entrez la clef.",
"totpStep3": "Entrez le code à usage unique fourni par l''application et cliquez sur Sauvegarder pour terminer.",
"totpManualStep2": "Ouvrez l''application et entrez la clef",
"totpManualStep3": "Utilisez les valeurs de configuration suivante si l''application les autorise",
"totpStep2": "Ouvrez l'application et scannez le code-barres ou entrez la clef.",
"totpStep3": "Entrez le code à usage unique fourni par l'application et cliquez sur Sauvegarder pour terminer.",
"totpManualStep2": "Ouvrez l'application et entrez la clef",
"totpManualStep3": "Utilisez les valeurs de configuration suivante si l'application les autorise",
"totpUnableToScan": "Impossible de scanner ?",
"totpScanBarcode": "Scanner le code-barres ?",
"totp.totp": "Basé sur le temps",
@ -976,34 +976,34 @@ export const messages= {
"totpDigits": "Chiffres",
"totpInterval": "Intervalle",
"totpCounter": "Compteur",
"missingUsernameMessage": "Veuillez entrer votre nom d''utilisateur.",
"missingUsernameMessage": "Veuillez entrer votre nom d'utilisateur.",
"missingFirstNameMessage": "Veuillez entrer votre prénom.",
"invalidEmailMessage": "Courriel invalide.",
"missingLastNameMessage": "Veuillez entrer votre nom.",
"missingEmailMessage": "Veuillez entrer votre courriel.",
"missingPasswordMessage": "Veuillez entrer votre mot de passe.",
"notMatchPasswordMessage": "Les mots de passe ne sont pas identiques",
"missingTotpMessage": "Veuillez entrer le code d''authentification.",
"missingTotpMessage": "Veuillez entrer le code d'authentification.",
"invalidPasswordExistingMessage": "Mot de passe existant invalide.",
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
"invalidTotpMessage": "Le code d''authentification est invalide.",
"usernameExistsMessage": "Le nom d''utilisateur existe déjà.",
"invalidTotpMessage": "Le code d'authentification est invalide.",
"usernameExistsMessage": "Le nom d'utilisateur existe déjà.",
"emailExistsMessage": "Le courriel existe déjà.",
"readOnlyUserMessage": "Vous ne pouvez pas mettre à jour votre compte car il est en lecture seule.",
"readOnlyPasswordMessage": "Vous ne pouvez pas mettre à jour votre mot de passe car votre compte est en lecture seule.",
"successTotpMessage": "L''authentification via téléphone mobile est configurée.",
"successTotpRemovedMessage": "L''authentification via téléphone mobile est supprimée.",
"successTotpMessage": "L'authentification via téléphone mobile est configurée.",
"successTotpRemovedMessage": "L'authentification via téléphone mobile est supprimée.",
"successGrantRevokedMessage": "Droit révoqué avec succès.",
"accountUpdatedMessage": "Votre compte a été mis à jour.",
"accountPasswordUpdatedMessage": "Votre mot de passe a été mis à jour.",
"missingIdentityProviderMessage": "Le fournisseur d''identité n''est pas spécifié.",
"missingIdentityProviderMessage": "Le fournisseur d'identité n'est pas spécifié.",
"invalidFederatedIdentityActionMessage": "Action manquante ou invalide.",
"identityProviderNotFoundMessage": "Le fournisseur d''identité spécifié n''est pas trouvé.",
"federatedIdentityLinkNotActiveMessage": "Cette identité n''est plus active dorénavant.",
"federatedIdentityRemovingLastProviderMessage": "Vous ne pouvez pas supprimer votre dernière fédération d''identité sans avoir de mot de passe spécifié.",
"identityProviderRedirectErrorMessage": "Erreur de redirection vers le fournisseur d''identité.",
"identityProviderRemovedMessage": "Le fournisseur d''identité a été supprimé correctement.",
"identityProviderAlreadyLinkedMessage": "Le fournisseur d''identité retourné par {0} est déjà lié à un autre utilisateur.",
"identityProviderNotFoundMessage": "Le fournisseur d'identité spécifié n'est pas trouvé.",
"federatedIdentityLinkNotActiveMessage": "Cette identité n'est plus active dorénavant.",
"federatedIdentityRemovingLastProviderMessage": "Vous ne pouvez pas supprimer votre dernière fédération d'identité sans avoir de mot de passe spécifié.",
"identityProviderRedirectErrorMessage": "Erreur de redirection vers le fournisseur d'identité.",
"identityProviderRemovedMessage": "Le fournisseur d'identité a été supprimé correctement.",
"identityProviderAlreadyLinkedMessage": "Le fournisseur d'identité retourné par {0} est déjà lié à un autre utilisateur.",
"accountDisabledMessage": "Ce compte est désactivé, veuillez contacter votre administrateur.",
"accountTemporarilyDisabledMessage": "Ce compte est temporairement désactivé, veuillez contacter votre administrateur ou réessayez plus tard.",
"invalidPasswordMinLengthMessage": "Mot de passe invalide: longueur minimale {0}.",
@ -1011,8 +1011,8 @@ export const messages= {
"invalidPasswordMinDigitsMessage": "Mot de passe invalide: doit contenir au moins {0} chiffre(s).",
"invalidPasswordMinUpperCaseCharsMessage": "Mot de passe invalide: doit contenir au moins {0} lettre(s) en majuscule.",
"invalidPasswordMinSpecialCharsMessage": "Mot de passe invalide: doit contenir au moins {0} caractère(s) spéciaux.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide: ne doit pas être identique au nom d''utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide: ne valide pas l''expression rationnelle.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide: ne doit pas être identique au nom d'utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide: ne valide pas l'expression rationnelle.",
"invalidPasswordHistoryMessage": "Mot de passe invalide: ne doit pas être égal aux {0} derniers mots de passe."
},
"it": {
@ -1027,7 +1027,7 @@ export const messages= {
"editAccountHtmlTitle": "Modifica Account",
"personalInfoHtmlTitle": "Informazioni personali",
"federatedIdentitiesHtmlTitle": "Identità federate",
"accountLogHtmlTitle": "Log dell''account",
"accountLogHtmlTitle": "Log dell'account",
"changePasswordHtmlTitle": "Cambia password",
"deviceActivityHtmlTitle": "Attività dei dispositivi",
"sessionsHtmlTitle": "Sessioni",
@ -1037,9 +1037,9 @@ export const messages= {
"linkedAccountsHtmlTitle": "Account collegati",
"accountManagementWelcomeMessage": "Benvenuto nella gestione degli account di Keycloak",
"personalInfoIntroMessage": "Gestisci le tue informazioni di base",
"accountSecurityTitle": "Sicurezza dell''account",
"accountSecurityIntroMessage": "Controlla la tua password e gli accessi dell''account",
"applicationsIntroMessage": "Traccia e gestisci i permessi delle applicazioni nell''accesso al tuo account",
"accountSecurityTitle": "Sicurezza dell'account",
"accountSecurityIntroMessage": "Controlla la tua password e gli accessi dell'account",
"applicationsIntroMessage": "Traccia e gestisci i permessi delle applicazioni nell'accesso al tuo account",
"resourceIntroMessage": "Condividi le tue risorse tra i membri del team",
"passwordLastUpdateMessage": "La tua password è stata aggiornata il",
"updatePasswordTitle": "Aggiornamento password",
@ -1092,7 +1092,7 @@ export const messages= {
"role_manage-events": "Gestisci eventi",
"role_view-profile": "Visualizza profilo",
"role_manage-account": "Gestisci account",
"role_manage-account-links": "Gestisci i link dell''account",
"role_manage-account-links": "Gestisci i link dell'account",
"role_manage-consent": "Gestisci consensi",
"role_read-token": "Leggi token",
"role_offline-access": "Accesso offline",
@ -1105,7 +1105,7 @@ export const messages= {
"client_broker": "Broker",
"requiredFields": "Campi obbligatori",
"allFieldsRequired": "Tutti campi obbligatori",
"backToApplication": "&laquo; Torna all''applicazione",
"backToApplication": "&laquo; Torna all'applicazione",
"backTo": "Torna a {0}",
"date": "Data",
"event": "Evento",
@ -1136,14 +1136,14 @@ export const messages= {
"configureAuthenticators": "Autenticatori configurati",
"mobile": "Dispositivo mobile",
"totpStep1": "Installa una delle seguenti applicazioni sul tuo dispositivo mobile",
"totpStep2": "Apri l''applicazione e scansiona il codice QR",
"totpStep3": "Scrivi il codice monouso fornito dall''applicazione e clicca Salva per completare il setup.",
"totpStep2": "Apri l'applicazione e scansiona il codice QR",
"totpStep3": "Scrivi il codice monouso fornito dall'applicazione e clicca Salva per completare il setup.",
"totpStep3DeviceName": "Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione.",
"totpManualStep2": "Apri l''applicazione e scrivi la chiave",
"totpManualStep3": "Usa le seguenti impostazioni se l''applicazione lo consente",
"totpManualStep2": "Apri l'applicazione e scrivi la chiave",
"totpManualStep3": "Usa le seguenti impostazioni se l'applicazione lo consente",
"totpUnableToScan": "Non riesci a scansionare il codice QR?",
"totpScanBarcode": "Vuoi scansionare il codice QR?",
"totp.totp": "Basato sull''ora",
"totp.totp": "Basato sull'ora",
"totp.hotp": "Basato sul contatore",
"totpType": "Tipo",
"totpAlgorithm": "Algoritmo",
@ -1155,7 +1155,7 @@ export const messages= {
"missingFirstNameMessage": "Inserisci il nome.",
"invalidEmailMessage": "Indirizzo email non valido.",
"missingLastNameMessage": "Inserisci il cognome.",
"missingEmailMessage": "Inserisci l''indirizzo email.",
"missingEmailMessage": "Inserisci l'indirizzo email.",
"missingPasswordMessage": "Inserisci la password.",
"notMatchPasswordMessage": "Le password non coincidono.",
"invalidUserMessage": "Utente non valido",
@ -1176,16 +1176,16 @@ export const messages= {
"accountPasswordUpdatedMessage": "La tua password è stata aggiornata.",
"missingIdentityProviderMessage": "Identity provider non specificato.",
"invalidFederatedIdentityActionMessage": "Azione non valida o mancante.",
"identityProviderNotFoundMessage": "L''identity provider specificato non è stato trovato.",
"identityProviderNotFoundMessage": "L'identity provider specificato non è stato trovato.",
"federatedIdentityLinkNotActiveMessage": "Questo identity non è più attivo.",
"federatedIdentityRemovingLastProviderMessage": "Non puoi rimuovere l''ultima identità federata poiché non hai più la password.",
"identityProviderRedirectErrorMessage": "Il reindirizzamento all''identity provider è fallito.",
"federatedIdentityRemovingLastProviderMessage": "Non puoi rimuovere l'ultima identità federata poiché non hai più la password.",
"identityProviderRedirectErrorMessage": "Il reindirizzamento all'identity provider è fallito.",
"identityProviderRemovedMessage": "Identity provider eliminato correttamente.",
"identityProviderAlreadyLinkedMessage": "L''identità federata restituita da {0} è già collegata ad un altro utente.",
"identityProviderAlreadyLinkedMessage": "L'identità federata restituita da {0} è già collegata ad un altro utente.",
"staleCodeAccountMessage": "La pagina è scaduta. Prova di nuovo.",
"consentDenied": "Consenso negato.",
"accountDisabledMessage": "Account disabilitato, contatta l''amministratore.",
"accountTemporarilyDisabledMessage": "L''account è temporaneamente disabilitato, contatta l''amministratore o riprova più tardi.",
"accountDisabledMessage": "Account disabilitato, contatta l'amministratore.",
"accountTemporarilyDisabledMessage": "L'account è temporaneamente disabilitato, contatta l'amministratore o riprova più tardi.",
"invalidPasswordMinLengthMessage": "Password non valida: lunghezza minima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Password non valida: deve contenere almeno {0} caratteri minuscoli.",
"invalidPasswordMinDigitsMessage": "Password non valida: deve contenere almeno {0} numeri.",
@ -1246,20 +1246,20 @@ export const messages= {
"identityProvider": "Identity provider",
"identityProviderMessage": "Collegare il tuo account con gli identity provider che hai configurato",
"socialLogin": "Social Login",
"userDefined": "Definito dall''utente",
"userDefined": "Definito dall'utente",
"removeAccess": "Rimuovi accesso",
"removeAccessMessage": "Devi concedere di nuovo l''accesso, se vuoi utilizzare l''account di questa applicazione.",
"authenticatorStatusMessage": "L''autenticazione a due fattori è attualmente",
"removeAccessMessage": "Devi concedere di nuovo l'accesso, se vuoi utilizzare l'account di questa applicazione.",
"authenticatorStatusMessage": "L'autenticazione a due fattori è attualmente",
"authenticatorFinishSetUpTitle": "La tua autenticazione a due fattori",
"authenticatorFinishSetUpMessage": "Ogni volta che effettui l''accesso al tuo account Keycloak, ti verrà richiesto di fornire il tuo codice di autenticazione a due fattori.",
"authenticatorSubTitle": "Imposta l''autenticazione a due fattori",
"authenticatorSubMessage": "Per incrementare la sicurezza del tuo account, attiva almeno uno dei metodi disponibili per l''autenticazione a due fattori.",
"authenticatorFinishSetUpMessage": "Ogni volta che effettui l'accesso al tuo account Keycloak, ti verrà richiesto di fornire il tuo codice di autenticazione a due fattori.",
"authenticatorSubTitle": "Imposta l'autenticazione a due fattori",
"authenticatorSubMessage": "Per incrementare la sicurezza del tuo account, attiva almeno uno dei metodi disponibili per l'autenticazione a due fattori.",
"authenticatorMobileTitle": "Autenticatore mobile",
"authenticatorMobileMessage": "Utilizza l''autenticatore mobile per ottenere i codici di verifica per l''autenticazione a due fattori.",
"authenticatorMobileFinishSetUpMessage": "L''autenticatore è stato collegato al tuo telefono.",
"authenticatorMobileMessage": "Utilizza l'autenticatore mobile per ottenere i codici di verifica per l'autenticazione a due fattori.",
"authenticatorMobileFinishSetUpMessage": "L'autenticatore è stato collegato al tuo telefono.",
"authenticatorActionSetup": "Set up",
"authenticatorSMSTitle": "Codice SMS",
"authenticatorSMSMessage": "Keycloak invierà il codice di verifica al tuo telefono per l''autenticazione a due fattori.",
"authenticatorSMSMessage": "Keycloak invierà il codice di verifica al tuo telefono per l'autenticazione a due fattori.",
"authenticatorSMSFinishSetUpMessage": "I messaggi di testo vengono inviati a",
"authenticatorDefaultStatus": "Default",
"authenticatorChangePhone": "Cambia numero di telefono",
@ -1268,9 +1268,9 @@ export const messages= {
"authenticatorBackupCodesFinishSetUpMessage": "Sono stati generati dodici codici di backup. Ognuno può essere usato una sola volta.",
"authenticatorMobileSetupTitle": "Setup autenticatore mobile",
"smscodeIntroMessage": "Inserisci il tuo numero di telefono e ti verrà inviato un codice di verifica.",
"mobileSetupStep1": "Installa un''applicazione di autenticazione sul tuo telefono. Sono supportate le applicazioni qui elencate.",
"mobileSetupStep2": "Apri l''applicazione e scansiona il codice QR:",
"mobileSetupStep3": "Inserisci il codice monouso fornito dall''applicazione e clicca Salva per completare il setup.",
"mobileSetupStep1": "Installa un'applicazione di autenticazione sul tuo telefono. Sono supportate le applicazioni qui elencate.",
"mobileSetupStep2": "Apri l'applicazione e scansiona il codice QR:",
"mobileSetupStep3": "Inserisci il codice monouso fornito dall'applicazione e clicca Salva per completare il setup.",
"scanBarCode": "Vuoi scansionare il codice QR?",
"enterBarCode": "Inserisci il codice monouso",
"doCopy": "Copia",
@ -1289,7 +1289,7 @@ export const messages= {
"backupCodesTips-2": "Questi codici sono stati generati il",
"generateNewBackupCodes": "Genera dei nuovi codici di backup",
"backupCodesTips-3": "Quando generi dei nuovi codici di backup, quelli attuali non funzioneranno più.",
"backtoAuthenticatorPage": "Torna alla pagina dell''autenticatore",
"backtoAuthenticatorPage": "Torna alla pagina dell'autenticatore",
"resources": "Risorse",
"sharedwithMe": "Condiviso con me",
"share": "Condiviso",
@ -1307,10 +1307,10 @@ export const messages= {
"addPeople": "Aggiungi persone con le quali condividere la tua risorsa",
"addTeam": "Aggiungi gruppi con i quali condividere la tua risorsa",
"myPermissions": "Miei permessi",
"waitingforApproval": "Attesa dell''approvazione",
"waitingforApproval": "Attesa dell'approvazione",
"anyPermission": "Qualsiasi permesso",
"openshift.scope.user_info": "Informazioni utente",
"openshift.scope.user_check-access": "Informazioni per l''accesso dell''utente",
"openshift.scope.user_check-access": "Informazioni per l'accesso dell'utente",
"openshift.scope.user_full": "Accesso completo",
"openshift.scope.list-projects": "Elenca progetti"
},
@ -2734,7 +2734,7 @@ export const messages= {
"mobile": "Mobil",
"totpStep1": "Akıllı Telefonunuza aşağıdaki uygulamalardan birini yükleyin:",
"totpStep2": "Uygulamayıın ve barkodu okutun.",
"totpStep3": "Uygulama tarafından oluşturulan tek seferlik kodu girin ve Kaydet''i tıklayın.",
"totpStep3": "Uygulama tarafından oluşturulan tek seferlik kodu girin ve Kaydet'i tıklayın.",
"totpManualStep2": "Uygulamayıın ve aşağıdaki anahtarı girin.",
"totpManualStep3": "Bunları uygulama için özelleştirebilirseniz aşağıdaki yapılandırma değerlerini kullanın:",
"totpUnableToScan": "Barkodu tarayamıyor musunuz?",
@ -2858,7 +2858,7 @@ export const messages= {
"authenticatorSubTitle": "İki Faktörlü Kimlik Doğrulamayı Ayarlama",
"authenticatorSubMessage": "Hesabınızın güvenliğini artırmak için mevcut iki faktörlü kimlik doğrulama yöntemlerinden en az birini etkinleştirin.",
"authenticatorMobileTitle": "Mobil Kimlik Doğrulayıcı",
"authenticatorMobileMessage": "Doğrulama kodlarını iki faktörlü kimlik doğrulama olarak almak için mobil Doğrulayıcı''yı kullanın.",
"authenticatorMobileMessage": "Doğrulama kodlarını iki faktörlü kimlik doğrulama olarak almak için mobil Doğrulayıcı'yı kullanın.",
"authenticatorMobileFinishSetUpMessage": "Doğrulayıcı, telefonunuza bağlı.",
"authenticatorActionSetup": "Kur",
"authenticatorSMSTitle": "SMS Kodu",
@ -2873,7 +2873,7 @@ export const messages= {
"smscodeIntroMessage": "Telefon numaranızı girin ve telefonunuza bir doğrulama kodu gönderilecektir.",
"mobileSetupStep1": "Telefonunuza bir kimlik doğrulama uygulaması yükleyin. Burada listelenen uygulamalar desteklenmektedir.",
"mobileSetupStep2": "Uygulamayıın ve barkodu tarayın.",
"mobileSetupStep3": "Uygulama tarafından sağlanan tek seferlik kodu girin ve kurulumu tamamlamak için Kaydet''e tıklayın.",
"mobileSetupStep3": "Uygulama tarafından sağlanan tek seferlik kodu girin ve kurulumu tamamlamak için Kaydet'e tıklayın.",
"scanBarCode": "Barkodu taramak ister misiniz?",
"enterBarCode": "Tek seferlik kodu girin",
"doCopy": "Kopyala",
@ -3060,5 +3060,5 @@ export const messages= {
"locale_ru": "Русский",
"locale_zh-CN": "中文简体"
}
} as const;
};
/* spell-checker: enable */

View File

@ -2,7 +2,7 @@
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const messages= {
export const kcMessages= {
"ca": {
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
@ -10,8 +10,8 @@ export const messages= {
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d''usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l''expressió regular."
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressió regular."
},
"de": {
"invalidPasswordMinLengthMessage": "Ungültiges Passwort: muss mindestens {0} Zeichen beinhalten.",
@ -77,8 +77,8 @@ export const messages= {
"invalidPasswordMinDigitsMessage": "Mot de passe invalide : doit contenir au moins {0} chiffre(s).",
"invalidPasswordMinUpperCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en majuscule.",
"invalidPasswordMinSpecialCharsMessage": "Mot de passe invalide : doit contenir au moins {0} caractère(s) spéciaux.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide : ne doit pas être identique au nom d''utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide : ne valide pas l''expression rationnelle.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide : ne doit pas être identique au nom d'utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide : ne valide pas l'expression rationnelle.",
"invalidPasswordHistoryMessage": "Mot de passe invalide : ne doit pas être égal aux {0} derniers mot de passe."
},
"it": {},
@ -240,5 +240,5 @@ export const messages= {
"pairwiseFailedToGetRedirectURIs": "无法从服务器获得重定向URL",
"pairwiseRedirectURIsMismatch": "客户端的重定向URI与服务器端获取的URI配置不匹配。"
}
} as const;
};
/* spell-checker: enable */

View File

@ -2,29 +2,29 @@
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const messages= {
export const kcMessages= {
"ca": {
"emailVerificationSubject": "Verificació d''email",
"emailVerificationBody": "Algú ha creat un compte de {2} amb aquesta adreça de correu electrònic. Si has estat tu, fes clic a l''enllaç següent per verificar la teva adreça de correu electrònic.\n\n{0}\n\nAquest enllaç expirarà en {1} minuts.\n\nSi tu no has creat aquest compte, simplement ignora aquest missatge.",
"emailVerificationBodyHtml": "<p>Algú ha creat un compte de {2} amb aquesta adreça de correu electrònic. Si has estat tu, fes clic a l''enllaç següent per verificar la teva adreça de correu electrònic.</p><p><a href=\"{0}\">{0}</a></p><p> Aquest enllaç expirarà en {1} minuts.</p><p> Si tu no has creat aquest compte, simplement ignora aquest missatge.</p>",
"emailVerificationSubject": "Verificació d'email",
"emailVerificationBody": "Algú ha creat un compte de {2} amb aquesta adreça de correu electrònic. Si has estat tu, fes clic a l'enllaç següent per verificar la teva adreça de correu electrònic.\n\n{0}\n\nAquest enllaç expirarà en {1} minuts.\n\nSi tu no has creat aquest compte, simplement ignora aquest missatge.",
"emailVerificationBodyHtml": "<p>Algú ha creat un compte de {2} amb aquesta adreça de correu electrònic. Si has estat tu, fes clic a l'enllaç següent per verificar la teva adreça de correu electrònic.</p><p><a href=\"{0}\">{0}</a></p><p> Aquest enllaç expirarà en {1} minuts.</p><p> Si tu no has creat aquest compte, simplement ignora aquest missatge.</p>",
"passwordResetSubject": "Reinicia contrasenya",
"passwordResetBody": "Algú ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l''enllaç següent per a reiniciar-les.\n\n{0}\n\nAquest enllaç expirarà en {1} minuts.\n\nSi no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzarà cap canvi.",
"passwordResetBodyHtml": "<p>Algú ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l''enllaç següent per a reiniciar-les.</p><p><a href=\"{0}\">{0}</a></p><p>Aquest enllaç expirarà en {1} minuts.</p><p>Si no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzarà cap canvi.</p>",
"passwordResetBody": "Algú ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l'enllaç següent per a reiniciar-les.\n\n{0}\n\nAquest enllaç expirarà en {1} minuts.\n\nSi no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzarà cap canvi.",
"passwordResetBodyHtml": "<p>Algú ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l'enllaç següent per a reiniciar-les.</p><p><a href=\"{0}\">{0}</a></p><p>Aquest enllaç expirarà en {1} minuts.</p><p>Si no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzarà cap canvi.</p>",
"executeActionsSubject": "Actualitza el teu compte",
"executeActionsBody": "L''administrador ha sol·licitat que actualitzis el teu compte de {2}. Fes clic a l''enllaç inferior per iniciar aquest procés.\n\n{0}\n\nAquest enllaç expirarà en {1} minutes.\n\nSi no estàs al tant que l''administrador hagi sol·licitat això, simplement ignora aquest missatge i no es realitzarà cap canvi.",
"executeActionsBodyHtml": "<p>L''administrador ha sol·licitat que actualitzis el teu compte de {2}. Fes clic a l''enllaç inferior per iniciar aquest procés.</p><p><a href=\"{0}\">{0}</a></p><p>Aquest enllaç expirarà en {1} minutes.</p><p>Si no estàs al tant que l''administrador hagi sol·licitat això, simplement ignora aquest missatge i no es realitzarà cap canvi.</p>",
"eventLoginErrorSubject": "Fallada en l''inici de sessió",
"eventLoginErrorBody": "S''ha detectat un intent d''accés fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.",
"eventLoginErrorBodyHtml": "<p>S''ha detectat un intent d''accés fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.</p>",
"executeActionsBody": "L'administrador ha sol·licitat que actualitzis el teu compte de {2}. Fes clic a l'enllaç inferior per iniciar aquest procés.\n\n{0}\n\nAquest enllaç expirarà en {1} minutes.\n\nSi no estàs al tant que l'administrador hagi sol·licitat això, simplement ignora aquest missatge i no es realitzarà cap canvi.",
"executeActionsBodyHtml": "<p>L'administrador ha sol·licitat que actualitzis el teu compte de {2}. Fes clic a l'enllaç inferior per iniciar aquest procés.</p><p><a href=\"{0}\">{0}</a></p><p>Aquest enllaç expirarà en {1} minutes.</p><p>Si no estàs al tant que l'administrador hagi sol·licitat això, simplement ignora aquest missatge i no es realitzarà cap canvi.</p>",
"eventLoginErrorSubject": "Fallada en l'inici de sessió",
"eventLoginErrorBody": "S'ha detectat un intent d'accés fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.",
"eventLoginErrorBodyHtml": "<p>S'ha detectat un intent d'accés fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.</p>",
"eventRemoveTotpSubject": "Esborrat OTP",
"eventRemoveTotpBody": "OTP s''ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, per favor contacta amb l''administrador.",
"eventRemoveTotpBodyHtml": "<p>OTP s''ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador. </ P>",
"eventRemoveTotpBody": "OTP s'ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, per favor contacta amb l'administrador.",
"eventRemoveTotpBodyHtml": "<p>OTP s'ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador. </ P>",
"eventUpdatePasswordSubject": "Actualització de contrasenya",
"eventUpdatePasswordBody": "La teva contrasenya s''ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.",
"eventUpdatePasswordBodyHtml": "<p>La teva contrasenya s''ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.</p>",
"eventUpdatePasswordBody": "La teva contrasenya s'ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.",
"eventUpdatePasswordBodyHtml": "<p>La teva contrasenya s'ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.</p>",
"eventUpdateTotpSubject": "Actualització de OTP",
"eventUpdateTotpBody": "OTP s''ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.",
"eventUpdateTotpBodyHtml": "<p>OTP s''ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l''administrador.</p>"
"eventUpdateTotpBody": "OTP s'ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.",
"eventUpdateTotpBodyHtml": "<p>OTP s'ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.</p>"
},
"cs": {
"emailVerificationSubject": "Ověření e-mailu",
@ -108,17 +108,17 @@ export const messages= {
},
"en": {
"emailVerificationSubject": "Verify email",
"emailVerificationBody": "Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {3}.\n\nIf you didn''t create this account, just ignore this message.",
"emailVerificationBodyHtml": "<p>Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address</p><p><a href=\"{0}\">Link to e-mail address verification</a></p><p>This link will expire within {3}.</p><p>If you didn''t create this account, just ignore this message.</p>",
"emailVerificationBody": "Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {3}.\n\nIf you didn't create this account, just ignore this message.",
"emailVerificationBodyHtml": "<p>Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address</p><p><a href=\"{0}\">Link to e-mail address verification</a></p><p>This link will expire within {3}.</p><p>If you didn't create this account, just ignore this message.</p>",
"emailTestSubject": "[KEYCLOAK] - SMTP test message",
"emailTestBody": "This is a test message",
"emailTestBodyHtml": "<p>This is a test message</p>",
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody": "Someone wants to link your \"{1}\" account with \"{0}\" account of user {2} . If this was you, click the link below to link accounts\n\n{3}\n\nThis link will expire within {5}.\n\nIf you don''t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.",
"identityProviderLinkBodyHtml": "<p>Someone wants to link your <b>{1}</b> account with <b>{0}</b> account of user {2} . If this was you, click the link below to link accounts</p><p><a href=\"{3}\">Link to confirm account linking</a></p><p>This link will expire within {5}.</p><p>If you don''t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.</p>",
"identityProviderLinkBody": "Someone wants to link your \"{1}\" account with \"{0}\" account of user {2} . If this was you, click the link below to link accounts\n\n{3}\n\nThis link will expire within {5}.\n\nIf you don't want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.",
"identityProviderLinkBodyHtml": "<p>Someone wants to link your <b>{1}</b> account with <b>{0}</b> account of user {2} . If this was you, click the link below to link accounts</p><p><a href=\"{3}\">Link to confirm account linking</a></p><p>This link will expire within {5}.</p><p>If you don't want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.</p>",
"passwordResetSubject": "Reset password",
"passwordResetBody": "Someone just requested to change your {2} account''s credentials. If this was you, click on the link below to reset them.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don''t want to reset your credentials, just ignore this message and nothing will be changed.",
"passwordResetBodyHtml": "<p>Someone just requested to change your {2} account''s credentials. If this was you, click on the link below to reset them.</p><p><a href=\"{0}\">Link to reset credentials</a></p><p>This link will expire within {3}.</p><p>If you don''t want to reset your credentials, just ignore this message and nothing will be changed.</p>",
"passwordResetBody": "Someone just requested to change your {2} account's credentials. If this was you, click on the link below to reset them.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don't want to reset your credentials, just ignore this message and nothing will be changed.",
"passwordResetBodyHtml": "<p>Someone just requested to change your {2} account's credentials. If this was you, click on the link below to reset them.</p><p><a href=\"{0}\">Link to reset credentials</a></p><p>This link will expire within {3}.</p><p>If you don't want to reset your credentials, just ignore this message and nothing will be changed.</p>",
"executeActionsSubject": "Update Your Account",
"executeActionsBody": "Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.\n\n{0}\n\nThis link will expire within {4}.\n\nIf you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.",
"executeActionsBodyHtml": "<p>Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.</p><p><a href=\"{0}\">Link to account update</a></p><p>This link will expire within {4}.</p><p>If you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.</p>",
@ -175,37 +175,37 @@ export const messages= {
},
"fr": {
"emailVerificationSubject": "Vérification du courriel",
"emailVerificationBody": "Quelqu''un vient de créer un compte \"{2}\" avec votre courriel. Si vous êtes à l''origine de cette requête, veuillez cliquer sur le lien ci-dessous afin de vérifier votre adresse de courriel\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon, veuillez ignorer ce message.",
"emailVerificationBodyHtml": "<p>Quelqu''un vient de créer un compte \"{2}\" avec votre courriel. Si vous êtes à l''origine de cette requête, veuillez cliquer sur le lien ci-dessous afin de vérifier votre adresse de courriel</p><p><a href=\"{0}\">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon, veuillez ignorer ce message.</p>",
"emailVerificationBody": "Quelqu'un vient de créer un compte \"{2}\" avec votre courriel. Si vous êtes à l'origine de cette requête, veuillez cliquer sur le lien ci-dessous afin de vérifier votre adresse de courriel\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon, veuillez ignorer ce message.",
"emailVerificationBodyHtml": "<p>Quelqu'un vient de créer un compte \"{2}\" avec votre courriel. Si vous êtes à l'origine de cette requête, veuillez cliquer sur le lien ci-dessous afin de vérifier votre adresse de courriel</p><p><a href=\"{0}\">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon, veuillez ignorer ce message.</p>",
"passwordResetSubject": "Réinitialiser le mot de passe",
"passwordResetBody": "Quelqu''un vient de demander une réinitialisation de mot de passe pour votre compte {2}. Si vous êtes à l''origine de cette requête, veuillez cliquer sur le lien ci-dessous pour le mettre à jour.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.",
"passwordResetBodyHtml": "<p>Quelqu''un vient de demander une réinitialisation de mot de passe pour votre compte {2}. Si vous êtes à l''origine de cette requête, veuillez cliquer sur le lien ci-dessous pour le mettre à jour.</p><p><a href=\"{0}\">Lien pour réinitialiser votre mot de passe</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.</p>",
"passwordResetBody": "Quelqu'un vient de demander une réinitialisation de mot de passe pour votre compte {2}. Si vous êtes à l'origine de cette requête, veuillez cliquer sur le lien ci-dessous pour le mettre à jour.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.",
"passwordResetBodyHtml": "<p>Quelqu'un vient de demander une réinitialisation de mot de passe pour votre compte {2}. Si vous êtes à l'origine de cette requête, veuillez cliquer sur le lien ci-dessous pour le mettre à jour.</p><p><a href=\"{0}\">Lien pour réinitialiser votre mot de passe</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.</p>",
"executeActionsSubject": "Mettre à jour votre compte",
"executeActionsBody": "Votre administrateur vient de demander une mise à jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSi vous n''êtes pas à l''origine de cette requête, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.",
"executeActionsBodyHtml": "<p>Votre administrateur vient de demander une mise à jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.</p><p><a href=\"{0}\">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Si vous n''êtes pas à l''origine de cette requête, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.</p>",
"executeActionsBody": "Votre administrateur vient de demander une mise à jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSi vous n'êtes pas à l'origine de cette requête, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.",
"executeActionsBodyHtml": "<p>Votre administrateur vient de demander une mise à jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.</p><p><a href=\"{0}\">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Si vous n'êtes pas à l'origine de cette requête, veuillez ignorer ce message ; aucun changement ne sera effectué sur votre compte.</p>",
"eventLoginErrorSubject": "Erreur de connexion",
"eventLoginErrorBody": "Une tentative de connexion a été détectée sur votre compte {0} depuis {1}. Si vous n''êtes pas à l''origine de cette requête, veuillez contacter votre administrateur.",
"eventLoginErrorBodyHtml": "<p>Une tentative de connexion a été détectée sur votre compte {0} depuis {1}. Si vous n''êtes pas à l''origine de cette requête, veuillez contacter votre administrateur.</p>",
"eventLoginErrorBody": "Une tentative de connexion a été détectée sur votre compte {0} depuis {1}. Si vous n'êtes pas à l'origine de cette requête, veuillez contacter votre administrateur.",
"eventLoginErrorBodyHtml": "<p>Une tentative de connexion a été détectée sur votre compte {0} depuis {1}. Si vous n'êtes pas à l'origine de cette requête, veuillez contacter votre administrateur.</p>",
"eventRemoveTotpSubject": "Suppression du OTP",
"eventRemoveTotpBody": "Le OTP a été supprimé de votre compte {0} depuis {1}. Si vous n''étiez pas à l''origine de cette requête, veuillez contacter votre administrateur.",
"eventRemoveTotpBodyHtml": "<p>Le OTP a été supprimé de votre compte {0} depuis {1}. Si vous n''étiez pas à l''origine de cette requête, veuillez contacter votre administrateur.</p>",
"eventRemoveTotpBody": "Le OTP a été supprimé de votre compte {0} depuis {1}. Si vous n'étiez pas à l'origine de cette requête, veuillez contacter votre administrateur.",
"eventRemoveTotpBodyHtml": "<p>Le OTP a été supprimé de votre compte {0} depuis {1}. Si vous n'étiez pas à l'origine de cette requête, veuillez contacter votre administrateur.</p>",
"eventUpdatePasswordSubject": "Mise à jour du mot de passe",
"eventUpdatePasswordBody": "Votre mot de passe pour votre compte {0} a été modifié depuis {1}. Si vous n''étiez pas à l''origine de cette requête, veuillez contacter votre administrateur.",
"eventUpdatePasswordBodyHtml": "<p>Votre mot de passe pour votre compte {0} a été modifié depuis {1}. Si vous n''étiez pas à l''origine de cette requête, veuillez contacter votre administrateur.</p>",
"eventUpdatePasswordBody": "Votre mot de passe pour votre compte {0} a été modifié depuis {1}. Si vous n'étiez pas à l'origine de cette requête, veuillez contacter votre administrateur.",
"eventUpdatePasswordBodyHtml": "<p>Votre mot de passe pour votre compte {0} a été modifié depuis {1}. Si vous n'étiez pas à l'origine de cette requête, veuillez contacter votre administrateur.</p>",
"eventUpdateTotpSubject": "Mise à jour du OTP",
"eventUpdateTotpBody": "Le OTP a été mis à jour pour votre compte {0} depuis {1}. Si vous n''étiez pas à l''origine de cette requête, veuillez contacter votre administrateur.",
"eventUpdateTotpBodyHtml": "<p>Le OTP a été mis à jour pour votre compte {0} depuis {1}. Si vous n''étiez pas à l''origine de cette requête, veuillez contacter votre administrateur.</p>"
"eventUpdateTotpBody": "Le OTP a été mis à jour pour votre compte {0} depuis {1}. Si vous n'étiez pas à l'origine de cette requête, veuillez contacter votre administrateur.",
"eventUpdateTotpBodyHtml": "<p>Le OTP a été mis à jour pour votre compte {0} depuis {1}. Si vous n'étiez pas à l'origine de cette requête, veuillez contacter votre administrateur.</p>"
},
"it": {
"emailVerificationSubject": "Verifica l''email",
"emailVerificationSubject": "Verifica l'email",
"emailVerificationBody": "Qualcuno ha creato un account {2} con questo indirizzo email. Se sei stato tu, fai clic sul link seguente per verificare il tuo indirizzo email\n\n{0}\n\nQuesto link scadrà in {3}.\n\nSe non sei stato tu a creare questo account, ignora questo messaggio.",
"emailVerificationBodyHtml": "<p>Qualcuno ha creato un account {2} con questo indirizzo email. Se sei stato tu, fai clic sul link seguente per verificare il tuo indirizzo email</p><p><a href=\"{0}\">{0}</a></p><p>Questo link scadrà in {3}.</p><p>Se non sei stato tu a creare questo account, ignora questo messaggio.</p>",
"emailTestSubject": "[KEYCLOAK] - messaggio di test SMTP",
"emailTestBody": "Questo è un messaggio di test",
"emailTestBodyHtml": "<p>Questo è un messaggio di test</p>",
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody": "Qualcuno vuole associare il tuo account \"{1}\" con l''account \"{0}\" dell''utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account\n\n{3}\n\nQuesto link scadrà in {5}.\n\nSe non vuoi associare l''account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.",
"identityProviderLinkBodyHtml": "<p>Qualcuno vuole associare il tuo account <b>{1}</b> con l''account <b>{0}</b> dell''utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account</p><p><a href=\"{3}\">{3}</a></p><p>Questo link scadrà in {5}.</p><p>Se non vuoi associare l''account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.</p>",
"identityProviderLinkBody": "Qualcuno vuole associare il tuo account \"{1}\" con l'account \"{0}\" dell'utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account\n\n{3}\n\nQuesto link scadrà in {5}.\n\nSe non vuoi associare l'account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.",
"identityProviderLinkBodyHtml": "<p>Qualcuno vuole associare il tuo account <b>{1}</b> con l'account <b>{0}</b> dell'utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account</p><p><a href=\"{3}\">{3}</a></p><p>Questo link scadrà in {5}.</p><p>Se non vuoi associare l'account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.</p>",
"passwordResetSubject": "Reimposta la password",
"passwordResetBody": "Qualcuno ha appena richiesto di cambiare le credenziali di accesso al tuo account {2}. Se sei stato tu, fai clic sul link seguente per reimpostarle.\n\n{0}\n\nQuesto link e codice scadranno in {3}.\n\nSe non vuoi reimpostare le tue credenziali di accesso, ignora questo messaggio e non verrà effettuato nessun cambio.",
"passwordResetBodyHtml": "<p>Qualcuno ha appena richiesto di cambiare le credenziali di accesso al tuo account {2}. Se sei stato tu, fai clic sul link seguente per reimpostarle.</p><p><a href=\"{0}\">{0}</a></p><p>Questo link scadrà in {3}.</p><p>Se non vuoi reimpostare le tue credenziali di accesso, ignora questo messaggio e non verrà effettuato nessun cambio.</p>",
@ -213,22 +213,22 @@ export const messages= {
"executeActionsBody": "Il tuo amministratore ha appena richiesto un aggiornamento del tuo account {2} ed è necessario che tu esegua la/le seguente/i azione/i: {3}. Fai clic sul link seguente per iniziare questo processo.\n\n{0}\n\nQuesto link scadrà in {4}.\n\nSe non sei a conoscenza della richiesta del tuo amministratore, ignora questo messaggio e non verrà effettuato nessun cambio.",
"executeActionsBodyHtml": "<p>Il tuo amministratore ha appena richiesto un aggiornamento del tuo account {2} ed è necessario che tu esegua la/le seguente/i azione/i: {3}. Fai clic sul link seguente per iniziare questo processo.</p><p><a href=\"{0}\">Link to account update</a></p><p>Questo link scadrà in {4}.</p><p>Se non sei a conoscenza della richiesta del tuo amministratore, ignora questo messaggio e non verrà effettuato nessun cambio.</p>",
"eventLoginErrorSubject": "Errore di accesso",
"eventLoginErrorBody": "È stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.",
"eventLoginErrorBodyHtml": "<p>È stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.</p>",
"eventLoginErrorBody": "È stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventLoginErrorBodyHtml": "<p>È stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"eventRemoveTotpSubject": "Rimozione OTP (password temporanea valida una volta sola)",
"eventRemoveTotpBody": "La OTP (password temporanea valida una volta sola) è stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.",
"eventRemoveTotpBodyHtml": "<p>La OTP (password temporanea valida una volta sola) è stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.</p>",
"eventRemoveTotpBody": "La OTP (password temporanea valida una volta sola) è stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventRemoveTotpBodyHtml": "<p>La OTP (password temporanea valida una volta sola) è stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"eventUpdatePasswordSubject": "Aggiornamento password",
"eventUpdatePasswordBody": "La tua password è stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.",
"eventUpdatePasswordBodyHtml": "<p>La tua password è stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.</p>",
"eventUpdatePasswordBody": "La tua password è stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventUpdatePasswordBodyHtml": "<p>La tua password è stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"eventUpdateTotpSubject": "Aggiornamento OTP (password temporanea valida una volta sola)",
"eventUpdateTotpBody": "La OTP (password temporanea valida una volta sola) è stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.",
"eventUpdateTotpBodyHtml": "<p>La OTP (password temporanea valida una volta sola) è stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.</p>",
"eventUpdateTotpBody": "La OTP (password temporanea valida una volta sola) è stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventUpdateTotpBodyHtml": "<p>La OTP (password temporanea valida una volta sola) è stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"requiredAction.CONFIGURE_TOTP": "Configurazione OTP",
"requiredAction.terms_and_conditions": "Termini e condizioni",
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
"requiredAction.UPDATE_PROFILE": "Aggiornamento profilo",
"requiredAction.VERIFY_EMAIL": "Verifica dell''indirizzo email",
"requiredAction.VERIFY_EMAIL": "Verifica dell'indirizzo email",
"linkExpirationFormatter.timePeriodUnit.seconds": "secondi",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "secondo",
"linkExpirationFormatter.timePeriodUnit.minutes": "minuti",
@ -581,18 +581,18 @@ export const messages= {
"executeActionsBody": "Yöneticiniz aşağıdaki işlemleri gerçekleştirerek {2} hesabınızı güncelledi: {3}. Bu işlemi başlatmak için aşağıdaki linke tıklayın.\n\n{0}\n\nBu bağlantının süresi {4} içerisinde sona erecek.\n\nYöneticinizin bunu istediğinden habersizseniz, bu mesajı göz ardı edin ve hiçbir şey değişmez.",
"executeActionsBodyHtml": "<p>Yöneticiniz aşağıdaki işlemleri gerçekleştirerek {2} hesabınızı güncelledi: {3}. Bu işlemi başlatmak için aşağıdaki linke tıklayın.</p><p><a href=\"{0}\">Hesap güncelleme bağlantısı</a></p><p>Bu bağlantının süresi {4} içerisinde sona erecek.</p><p>Yöneticinizin bunu istediğinden habersizseniz, bu mesajı göz ardı edin ve hiçbir şey değişmez.</p>",
"eventLoginErrorSubject": "Giriş hatası",
"eventLoginErrorBody": "{1} ''den {0} tarihinde başarısız bir giriş denemesi yapıldı. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.",
"eventLoginErrorBodyHtml": "<p>{1} ''den {0} tarihinde başarısız bir giriş denemesi yapıldı. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.</p>",
"eventRemoveTotpSubject": "OTP''yi kaldır",
"eventLoginErrorBody": "{1} 'den {0} tarihinde başarısız bir giriş denemesi yapıldı. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.",
"eventLoginErrorBodyHtml": "<p>{1} 'den {0} tarihinde başarısız bir giriş denemesi yapıldı. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.</p>",
"eventRemoveTotpSubject": "OTP'yi kaldır",
"eventRemoveTotpBody": "OTP, {0} tarihinden {1} tarihinde hesabınızdan kaldırıldı. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.",
"eventRemoveTotpBodyHtml": "<p>OTP, {0} tarihinden {1} tarihinde hesabınızdan kaldırıldı. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.</p>",
"eventUpdatePasswordSubject": "Şifreyi güncelle",
"eventUpdatePasswordBody": "Şifreniz {0} tarihinde {0} tarihinde değiştirildi. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.",
"eventUpdatePasswordBodyHtml": "<p>Şifreniz {0} tarihinde {0} tarihinde değiştirildi. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.</p>",
"eventUpdateTotpSubject": "OTP''yi Güncelle",
"eventUpdateTotpSubject": "OTP'yi Güncelle",
"eventUpdateTotpBody": "OTP, {0} tarihinden {1} tarihinde hesabınız için güncellendi. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.",
"eventUpdateTotpBodyHtml": "<p>OTP, {0} tarihinden {1} tarihinde hesabınız için güncellendi. Bu siz değilseniz, lütfen yöneticiyle iletişime geçin.</p>",
"requiredAction.CONFIGURE_TOTP": "OTP''yi yapılandır",
"requiredAction.CONFIGURE_TOTP": "OTP'yi yapılandır",
"requiredAction.terms_and_conditions": "Şartlar ve Koşullar",
"requiredAction.UPDATE_PASSWORD": "Şifre Güncelleme",
"requiredAction.UPDATE_PROFILE": "Profilleri güncelle",
@ -634,5 +634,5 @@ export const messages= {
"eventUpdateTotpBody": "您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。",
"eventUpdateTotpBodyHtml": "<p>您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。</p>"
}
} as const;
};
/* spell-checker: enable */

View File

@ -2,10 +2,10 @@
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const messages= {
export const kcMessages= {
"ca": {
"doLogIn": "Inicia sessió",
"doRegister": "Registra''t",
"doRegister": "Registra't",
"doCancel": "Cancel·lar",
"doSubmit": "Envia",
"doYes": "Sí",
@ -20,7 +20,7 @@ export const messages= {
"kerberosNotConfiguredTitle": "Kerberos no configurat",
"bypassKerberosDetail": "O bé no estàs identificat mitjançant Kerberos o el teu navegador no està configurat per identificar-se mitjançant Kerberos. Si us plau fes clic per identificar-te per un altre mitjà.",
"kerberosNotSetUp": "Kerberos no està configurat. No pots identificar-te.",
"registerWithTitle": "Registra''t amb {0}",
"registerWithTitle": "Registra't amb {0}",
"registerWithTitleHtml": "{0}",
"loginTitle": "Inicia sessió a {0}",
"loginTitleHtml": "{0}",
@ -28,18 +28,18 @@ export const messages= {
"impersonateTitleHtml": "<strong>{0}</strong> Personifica Usuari",
"realmChoice": "Domini",
"unknownUser": "Usuari desconegut",
"loginTotpTitle": "Configura la teva aplicació d''identificació mòbil",
"loginTotpTitle": "Configura la teva aplicació d'identificació mòbil",
"loginProfileTitle": "Actualitza la informació del teu compte",
"loginTimeout": "Has trigat massa a identificar-te. Inicia de nou la identificació.",
"oauthGrantTitle": "Concessió OAuth",
"oauthGrantTitleHtml": "{0}",
"errorTitle": "Ho sentim...",
"errorTitleHtml": "Ho <strong>sentim</strong>...",
"emailVerifyTitle": "Verificació de l''email",
"emailVerifyTitle": "Verificació de l'email",
"emailForgotTitle": "Has oblidat la teva contrasenya?",
"updatePasswordTitle": "Modificació de contrasenya",
"codeSuccessTitle": "Codi d''èxit",
"codeErrorTitle": "Codi d''error: {0}",
"codeSuccessTitle": "Codi d'èxit",
"codeErrorTitle": "Codi d'error: {0}",
"termsTitle": "Termes i Condicions",
"termsTitleHtml": "Termes i Condicions",
"termsText": "<p>Termes i condicions a definir</p>",
@ -60,7 +60,7 @@ export const messages= {
"passwordNew": "Nova contrasenya",
"passwordNewConfirm": "Confirma la nova contrasenya",
"rememberMe": "Seguir connectat",
"authenticatorCode": "Codi d''identificació",
"authenticatorCode": "Codi d'identificació",
"address": "Adreça",
"street": "Carrer",
"locality": "Ciutat o Municipi",
@ -69,17 +69,17 @@ export const messages= {
"country": "País",
"emailVerified": "Email verificat",
"gssDelegationCredential": "GSS Delegation Credential",
"loginTotpStep1": "Instal·la <a href=\"https://freeotp.github.io/\" target=\"_blank\">FreeOTP</a> o Google Authenticator al teu telèfon mòbil. Les dues aplicacions estan disponibles a <a href=\"https://play.google.com\">Google Play</a> i en l''App Store d''Apple.",
"loginTotpStep2": "Obre l''aplicació i escaneja el codi o introdueix la clau.",
"loginTotpStep3": "Introdueix el codi únic que et mostra l''aplicació d''autenticació i fes clic a Envia per finalitzar la configuració",
"loginOtpOneTime": "Codi d''un sol ús",
"oauthGrantRequest": "Vols permetre aquests privilegis d''accés?",
"loginTotpStep1": "Instal·la <a href=\"https://freeotp.github.io/\" target=\"_blank\">FreeOTP</a> o Google Authenticator al teu telèfon mòbil. Les dues aplicacions estan disponibles a <a href=\"https://play.google.com\">Google Play</a> i en l'App Store d'Apple.",
"loginTotpStep2": "Obre l'aplicació i escaneja el codi o introdueix la clau.",
"loginTotpStep3": "Introdueix el codi únic que et mostra l'aplicació d'autenticació i fes clic a Envia per finalitzar la configuració",
"loginOtpOneTime": "Codi d'un sol ús",
"oauthGrantRequest": "Vols permetre aquests privilegis d'accés?",
"inResource": "a",
"emailVerifyInstruction1": "T''hem enviat un email amb instruccions per verificar el teu email.",
"emailVerifyInstruction1": "T'hem enviat un email amb instruccions per verificar el teu email.",
"emailVerifyInstruction2": "No has rebut un codi de verificació al teu email?",
"emailVerifyInstruction3": "per reenviar l''email.",
"emailVerifyInstruction3": "per reenviar l'email.",
"backToLogin": "&laquo; Torna a la identificació",
"emailInstruction": "Indica el teu usuari o email i t''enviarem instruccions indicant com generar una nova contrasenya.",
"emailInstruction": "Indica el teu usuari o email i t'enviarem instruccions indicant com generar una nova contrasenya.",
"copyCodeInstruction": "Si us plau, copia i enganxa aquest codi a la teva aplicació:",
"personalInfo": "Informació personal:",
"role_admin": "Admin",
@ -91,11 +91,11 @@ export const messages= {
"role_view-applications": "Veure aplicacions",
"role_view-clients": "Veure clients",
"role_view-events": "Veure events",
"role_view-identity-providers": "Veure proveïdors d''identitat",
"role_view-identity-providers": "Veure proveïdors d'identitat",
"role_manage-realm": "Gestionar domini",
"role_manage-users": "Gestionar usuaris",
"role_manage-applications": "Gestionar aplicacions",
"role_manage-identity-providers": "Gestionar proveïdors d''identitat",
"role_manage-identity-providers": "Gestionar proveïdors d'identitat",
"role_manage-clients": "Gestionar clients",
"role_manage-events": "Gestionar events",
"role_view-profile": "Veure perfil",
@ -103,79 +103,79 @@ export const messages= {
"role_read-token": "Llegir token",
"role_offline-access": "Accés sense connexió",
"client_account": "Compte",
"client_security-admin-console": "Consola d''Administració de Seguretat",
"client_security-admin-console": "Consola d'Administració de Seguretat",
"client_realm-management": "Gestió del domini",
"client_broker": "Broker",
"invalidUserMessage": "Usuari o contrasenya incorrectes.",
"invalidEmailMessage": "Email no vàlid",
"accountDisabledMessage": "El compte està desactivat, contacta amb l''administrador.",
"accountTemporarilyDisabledMessage": "El compte està temporalment desactivat, contacta amb l''administrador o intenta-ho de nou més tard.",
"expiredCodeMessage": "S''ha esgotat el temps màxim per a la identificació. Si us plau identifica''t de nou.",
"accountDisabledMessage": "El compte està desactivat, contacta amb l'administrador.",
"accountTemporarilyDisabledMessage": "El compte està temporalment desactivat, contacta amb l'administrador o intenta-ho de nou més tard.",
"expiredCodeMessage": "S'ha esgotat el temps màxim per a la identificació. Si us plau identifica't de nou.",
"missingFirstNameMessage": "Si us plau indica el teu nom.",
"missingLastNameMessage": "Si us plau indica els teus cognoms.",
"missingEmailMessage": "Si us plau indica el teu email.",
"missingUsernameMessage": "Si us plau indica el teu usuari.",
"missingPasswordMessage": "Si us plau indica la teva contrasenya.",
"missingTotpMessage": "Si us plau indica el teu codi d''autenticació",
"missingTotpMessage": "Si us plau indica el teu codi d'autenticació",
"notMatchPasswordMessage": "Les contrasenyes no coincideixen.",
"invalidPasswordExistingMessage": "La contrasenya actual no és correcta.",
"invalidPasswordConfirmMessage": "La confirmació de contrasenya no coincideix.",
"invalidTotpMessage": "El codi d''autenticació no és vàlid.",
"usernameExistsMessage": "El nom d''usuari ja existeix",
"emailExistsMessage": "L''email ja existeix",
"invalidTotpMessage": "El codi d'autenticació no és vàlid.",
"usernameExistsMessage": "El nom d'usuari ja existeix",
"emailExistsMessage": "L'email ja existeix",
"federatedIdentityEmailExistsMessage": "Ja existeix un usuari amb aquest email. Si us plau accedeix a la gestió del teu compte per enllaçar-lo.",
"federatedIdentityUsernameExistsMessage": "Ja existeix un usuari amb aquest nom d''usuari. Si us plau accedeix a la gestió del teu compte per enllaçar-lo.",
"configureTotpMessage": "Has de configurar l''aplicació mòbil 'd'identificació per activar el teu compte.",
"updateProfileMessage": "Has d''actualitzar el teu perfil d''usuari per activar el teu compte.",
"federatedIdentityUsernameExistsMessage": "Ja existeix un usuari amb aquest nom d'usuari. Si us plau accedeix a la gestió del teu compte per enllaçar-lo.",
"configureTotpMessage": "Has de configurar l'aplicació mòbil 'd'identificació per activar el teu compte.",
"updateProfileMessage": "Has d'actualitzar el teu perfil d'usuari per activar el teu compte.",
"updatePasswordMessage": "Has de canviar la contrasenya per activar el teu compte.",
"verifyEmailMessage": "Has de verificar el teu email per activar el teu compte.",
"emailSentMessage": "En breu hauries de rebre un missatge amb més instruccions",
"emailSendErrorMessage": "Ha fallat l''enviament de l''email, si us plau intenta-ho de nou més tard.",
"accountUpdatedMessage": "El teu compte s''ha actualitzat.",
"accountPasswordUpdatedMessage": "La contrasenya s''ha actualitzat.",
"emailSendErrorMessage": "Ha fallat l'enviament de l'email, si us plau intenta-ho de nou més tard.",
"accountUpdatedMessage": "El teu compte s'ha actualitzat.",
"accountPasswordUpdatedMessage": "La contrasenya s'ha actualitzat.",
"noAccessMessage": "Sense accés",
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mínima {0}.",
"invalidPasswordMinDigitsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters numèrics.",
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d''usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l''expressió regular.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressió regular.",
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes.",
"failedToProcessResponseMessage": "Fallada en processar la resposta",
"httpsRequiredMessage": "HTTPS obligatori",
"realmNotEnabledMessage": "El domini no està activat",
"invalidRequestMessage": "Petició incorrecta",
"failedLogout": "Ha fallat la desconnexió.",
"unknownLoginRequesterMessage": "Sol·licitant d''identificació desconegut",
"loginRequesterNotEnabledMessage": "El sol·licitant d''inici de sessió està desactivat",
"unknownLoginRequesterMessage": "Sol·licitant d'identificació desconegut",
"loginRequesterNotEnabledMessage": "El sol·licitant d'inici de sessió està desactivat",
"bearerOnlyMessage": "Les aplicacions Bearer-only no poden iniciar sessió des del navegador.",
"directGrantsOnlyMessage": "Els clients de tipus Direct-grants-only no poden iniciar sessió des del navegador.",
"invalidRedirectUriMessage": "L''URI de redirecció no és correcta",
"invalidRedirectUriMessage": "L'URI de redirecció no és correcta",
"unsupportedNameIdFormatMessage": "NameIDFormat no suportat",
"invalidRequesterMessage": "Sol·licitant no vàlid",
"registrationNotAllowedMessage": "El registre no està permès",
"resetCredentialNotAllowedMessage": "El reinici de les credencials no està permès",
"permissionNotApprovedMessage": "Permís no aprovat.",
"noRelayStateInResponseMessage": "Sense estat de retransmissió en la resposta del proveïdor d''identitat.",
"identityProviderAlreadyLinkedMessage": "La identitat retornada pel proveïdor d''identitat ja està associada a un altre usuari.",
"noRelayStateInResponseMessage": "Sense estat de retransmissió en la resposta del proveïdor d'identitat.",
"identityProviderAlreadyLinkedMessage": "La identitat retornada pel proveïdor d'identitat ja està associada a un altre usuari.",
"insufficientPermissionMessage": "Permisos insuficients per enllaçar identitats.",
"couldNotProceedWithAuthenticationRequestMessage": "No s''ha pogut continuar amb la petició d''autenticació al proveïdor d''identitat.",
"couldNotObtainTokenMessage": "No s''ha pogut obtenir el codi del proveïdor d''identitat.",
"unexpectedErrorRetrievingTokenMessage": "Error inesperat obtenint el token del proveïdor d''identitat",
"unexpectedErrorHandlingResponseMessage": "Error inesperat processant la resposta del proveïdor d''identitat.",
"identityProviderAuthenticationFailedMessage": "Ha fallat l''autenticació. No ha estat possible autenticar-se en el proveïdor d''identitat.",
"couldNotSendAuthenticationRequestMessage": "No s''ha pogut enviar la petició d''identificació al proveïdor d''identitat.",
"unexpectedErrorHandlingRequestMessage": "Error inesperat durant la petició d''identificació al proveïdor d''identitat.",
"invalidAccessCodeMessage": "Codi d''accés no vàlid.",
"couldNotProceedWithAuthenticationRequestMessage": "No s'ha pogut continuar amb la petició d'autenticació al proveïdor d'identitat.",
"couldNotObtainTokenMessage": "No s'ha pogut obtenir el codi del proveïdor d'identitat.",
"unexpectedErrorRetrievingTokenMessage": "Error inesperat obtenint el token del proveïdor d'identitat",
"unexpectedErrorHandlingResponseMessage": "Error inesperat processant la resposta del proveïdor d'identitat.",
"identityProviderAuthenticationFailedMessage": "Ha fallat l'autenticació. No ha estat possible autenticar-se en el proveïdor d'identitat.",
"couldNotSendAuthenticationRequestMessage": "No s'ha pogut enviar la petició d'identificació al proveïdor d'identitat.",
"unexpectedErrorHandlingRequestMessage": "Error inesperat durant la petició d'identificació al proveïdor d'identitat.",
"invalidAccessCodeMessage": "Codi d'accés no vàlid.",
"sessionNotActiveMessage": "La sessió no està activa",
"invalidCodeMessage": "Hi ha hagut un error, si us plau identifica''t de nou des de la teva aplicació.",
"identityProviderUnexpectedErrorMessage": "Error no esperat intentant autenticar en el proveïdor d''identitat.",
"identityProviderNotFoundMessage": "No s''ha trobat cap proveïdor d''identitat.",
"invalidCodeMessage": "Hi ha hagut un error, si us plau identifica't de nou des de la teva aplicació.",
"identityProviderUnexpectedErrorMessage": "Error no esperat intentant autenticar en el proveïdor d'identitat.",
"identityProviderNotFoundMessage": "No s'ha trobat cap proveïdor d'identitat.",
"realmSupportsNoCredentialsMessage": "El domini no suporta cap tipus de credencials.",
"identityProviderNotUniqueMessage": "El domini suporta múltiples proveïdors d''identitat. No s''ha pogut determinar el proveïdor d''identitat que hauria de ser utilitzat per identificar-se.",
"identityProviderNotUniqueMessage": "El domini suporta múltiples proveïdors d'identitat. No s'ha pogut determinar el proveïdor d'identitat que hauria de ser utilitzat per identificar-se.",
"emailVerifiedMessage": "El teu email ha estat verificat.",
"backToApplication": "&laquo; Torna a l''aplicació",
"backToApplication": "&laquo; Torna a l'aplicació",
"missingParameterMessage": "Paràmetres que falten: {0}",
"clientNotFoundMessage": "Client no trobat",
"invalidParameterMessage": "Paràmetre no vàlid: {0}",
@ -401,7 +401,7 @@ export const messages= {
"clientDisabledMessage": "Klient byl zneplatněn.",
"invalidParameterMessage": "Neplatný parametr : {0}",
"alreadyLoggedIn": "Jste již přihlášeni.",
"differentUserAuthenticated": "Jste již v této relaci ověřeni jako jiný uživatel '' {0} ''. Nejdříve se odhlašte.",
"differentUserAuthenticated": "Jste již v této relaci ověřeni jako jiný uživatel ' {0} '. Nejdříve se odhlašte.",
"brokerLinkingSessionExpired": "Požadované propojení účtu brokerů, ale aktuální relace již není platná.",
"proceedWithAction": "&raquo; Klikněte zde pro pokračování",
"requiredAction.CONFIGURE_TOTP": "Konfigurovat OTP",
@ -631,7 +631,7 @@ export const messages= {
"clientDisabledMessage": "Client deaktiviert.",
"invalidParameterMessage": "Ungültiger Parameter: {0}",
"alreadyLoggedIn": "Sie sind bereits angemeldet.",
"differentUserAuthenticated": "Sie sind in dieser Session bereits mit einem anderen Benutzer ''{0}'' angemeldet. Bitte melden Sie sich zuerst ab.",
"differentUserAuthenticated": "Sie sind in dieser Session bereits mit einem anderen Benutzer '{0}' angemeldet. Bitte melden Sie sich zuerst ab.",
"brokerLinkingSessionExpired": "Broker Account Linking angefordert; Ihre Session ist allerdings nicht mehr gültig.",
"proceedWithAction": "&raquo; Klicken Sie hier um fortzufahren",
"requiredAction.CONFIGURE_TOTP": "Mehrfachauthentifizierung konfigurieren",
@ -750,11 +750,11 @@ export const messages= {
"oauthGrantRequest": "Do you grant these access privileges?",
"inResource": "in",
"emailVerifyInstruction1": "An email with instructions to verify your email address has been sent to you.",
"emailVerifyInstruction2": "Haven''t received a verification code in your email?",
"emailVerifyInstruction2": "Haven't received a verification code in your email?",
"emailVerifyInstruction3": "to re-send the email.",
"emailLinkIdpTitle": "Link {0}",
"emailLinkIdp1": "An email with instructions to link {0} account {1} with your {2} account has been sent to you.",
"emailLinkIdp2": "Haven''t received a verification code in your email?",
"emailLinkIdp2": "Haven't received a verification code in your email?",
"emailLinkIdp3": "to re-send the email.",
"emailLinkIdp4": "If you already verified the email in different browser",
"emailLinkIdp5": "to continue.",
@ -811,10 +811,10 @@ export const messages= {
"missingPasswordMessage": "Please specify password.",
"missingTotpMessage": "Please specify authenticator code.",
"missingTotpDeviceNameMessage": "Please specify device name.",
"notMatchPasswordMessage": "Passwords don''t match.",
"notMatchPasswordMessage": "Passwords don't match.",
"invalidPasswordExistingMessage": "Invalid existing password.",
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
"invalidPasswordConfirmMessage": "Password confirmation doesn''t match.",
"invalidPasswordConfirmMessage": "Password confirmation doesn't match.",
"invalidTotpMessage": "Invalid authenticator code.",
"usernameExistsMessage": "Username already exists.",
"emailExistsMessage": "Email already exists.",
@ -848,7 +848,7 @@ export const messages= {
"invalidPasswordNotUsernameMessage": "Invalid password: must not be equal to the username.",
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
"invalidPasswordGenericMessage": "Invalid password: new password doesn''t match password policies.",
"invalidPasswordGenericMessage": "Invalid password: new password doesn't match password policies.",
"failedToProcessResponseMessage": "Failed to process response",
"httpsRequiredMessage": "HTTPS required",
"realmNotEnabledMessage": "Realm not enabled",
@ -914,7 +914,7 @@ export const messages= {
"clientDisabledMessage": "Client disabled.",
"invalidParameterMessage": "Invalid parameter: {0}",
"alreadyLoggedIn": "You are already logged in.",
"differentUserAuthenticated": "You are already authenticated as different user ''{0}'' in this session. Please log out first.",
"differentUserAuthenticated": "You are already authenticated as different user '{0}' in this session. Please log out first.",
"brokerLinkingSessionExpired": "Requested broker account linking, but current session is no longer valid.",
"proceedWithAction": "&raquo; Click here to proceed",
"requiredAction.CONFIGURE_TOTP": "Configure OTP",
@ -1162,9 +1162,9 @@ export const messages= {
"doImpersonate": "Impersonate",
"kerberosNotConfigured": "Kerberos non configuré",
"kerberosNotConfiguredTitle": "Kerberos non configuré",
"bypassKerberosDetail": "Si vous n''êtes pas connecté via Kerberos ou bien que votre navigateur n''est pas configuré pour la connexion via Kerberos. Veuillez cliquer pour vous connecter via un autre moyen.",
"kerberosNotSetUp": "Kerberos n''est pas configuré. Connexion impossible.",
"registerTitle": "S''enregistrer",
"bypassKerberosDetail": "Si vous n'êtes pas connecté via Kerberos ou bien que votre navigateur n'est pas configuré pour la connexion via Kerberos. Veuillez cliquer pour vous connecter via un autre moyen.",
"kerberosNotSetUp": "Kerberos n'est pas configuré. Connexion impossible.",
"registerTitle": "S'enregistrer",
"registerWithTitle": "Enregistrement avec {0}",
"registerWithTitleHtml": "{0}",
"loginTitle": "Se connecter à {0}",
@ -1173,7 +1173,7 @@ export const messages= {
"impersonateTitleHtml": "<strong>{0}</strong> utilisateur impersonate",
"realmChoice": "Domaine",
"unknownUser": "Utilisateur inconnu",
"loginTotpTitle": "Configuration de l''authentification par mobile",
"loginTotpTitle": "Configuration de l'authentification par mobile",
"loginProfileTitle": "Mise à jour du compte",
"loginTimeout": "Le temps imparti pour la connexion est écoulé. Le processus de connexion redémarre depuis le début.",
"oauthGrantTitle": "OAuth Grant",
@ -1184,8 +1184,8 @@ export const messages= {
"emailForgotTitle": "Mot de passe oublié ?",
"updatePasswordTitle": "Mise à jour du mot de passe",
"codeSuccessTitle": "Code succès",
"codeErrorTitle": "Code d''erreur : {0}",
"displayUnsupported": "Type d''affichage demandé non supporté",
"codeErrorTitle": "Code d'erreur : {0}",
"displayUnsupported": "Type d'affichage demandé non supporté",
"browserRequired": "Navigateur requis pour se connecter",
"browserContinue": "Navigateur requis pour continuer la connexion",
"browserContinuePrompt": "Ouvrir le navigateur et continuer la connexion? [y/n]:",
@ -1195,11 +1195,11 @@ export const messages= {
"termsText": "<p>Termes et conditions à définir</p>",
"termsPlainText": "Termes et conditions à définir",
"recaptchaFailed": "Re-captcha invalide",
"recaptchaNotConfigured": "Re-captcha est requis, mais il n''est pas configuré",
"recaptchaNotConfigured": "Re-captcha est requis, mais il n'est pas configuré",
"consentDenied": "Consentement refusé.",
"noAccount": "Nouvel utilisateur ?",
"username": "Nom d''utilisateur",
"usernameOrEmail": "Nom d''utilisateur ou courriel",
"username": "Nom d'utilisateur",
"usernameOrEmail": "Nom d'utilisateur ou courriel",
"firstName": "Prénom",
"givenName": "Prénom",
"fullName": "Nom complet",
@ -1222,10 +1222,10 @@ export const messages= {
"gssDelegationCredential": "Accréditation de délégation GSS",
"loginTotpIntro": "Il est nécessaire de configurer un générateur One Time Password pour accéder à ce compte",
"loginTotpStep1": "Installez <a href=\"https://freeotp.github.io/\" target=\"_blank\">FreeOTP</a> ou bien Google Authenticator sur votre mobile. Ces deux applications sont disponibles sur <a href=\"https://play.google.com\">Google Play</a> et Apple App Store.",
"loginTotpStep2": "Ouvrez l''application et scannez le code-barres ou entrez la clef.",
"loginTotpStep3": "Entrez le code à usage unique fourni par l''application et cliquez sur Sauvegarder pour terminer.",
"loginTotpManualStep2": "Ouvrez l''application et saisissez la clé",
"loginTotpManualStep3": "Utilisez la configuration de valeur suivante si l''application permet son édition",
"loginTotpStep2": "Ouvrez l'application et scannez le code-barres ou entrez la clef.",
"loginTotpStep3": "Entrez le code à usage unique fourni par l'application et cliquez sur Sauvegarder pour terminer.",
"loginTotpManualStep2": "Ouvrez l'application et saisissez la clé",
"loginTotpManualStep3": "Utilisez la configuration de valeur suivante si l'application permet son édition",
"loginTotpUnableToScan": "Impossible de scanner?",
"loginTotpScanBarcode": "Scanner le code barre ?",
"loginOtpOneTime": "Code à usage unique",
@ -1236,23 +1236,23 @@ export const messages= {
"loginTotpCounter": "Compteur",
"loginTotp.totp": "Basé sur le temps",
"loginTotp.hotp": "Basé sur les compteurs",
"oauthGrantRequest": "Voulez-vous accorder ces privilèges d''accès ?",
"oauthGrantRequest": "Voulez-vous accorder ces privilèges d'accès ?",
"inResource": "dans",
"emailVerifyInstruction1": "Un courriel avec des instructions à suivre vous a été envoyé.",
"emailVerifyInstruction2": "Vous n''avez pas reçu de code dans le courriel ?",
"emailVerifyInstruction2": "Vous n'avez pas reçu de code dans le courriel ?",
"emailVerifyInstruction3": "pour renvoyer le courriel.",
"emailLinkIdpTitle": "Association avec {0}",
"emailLinkIdp1": "Un courriel avec des instructions pour associer le compte {1} sur {0} avec votre compte {2} vous a été envoyé.",
"emailLinkIdp2": "Vous n''avez pas reçu de code dans le courriel ?",
"emailLinkIdp2": "Vous n'avez pas reçu de code dans le courriel ?",
"emailLinkIdp3": "pour renvoyer le courriel.",
"emailLinkIdp4": "Si vous avez déjà vérifié votre courriel dans un autre navigateur",
"emailLinkIdp5": "pour continuer.",
"backToLogin": "&laquo; Retour à la connexion",
"emailInstruction": "Entrez votre nom d''utilisateur ou votre courriel ; un courriel va vous être envoyé vous permettant de créer un nouveau mot de passe.",
"emailInstruction": "Entrez votre nom d'utilisateur ou votre courriel ; un courriel va vous être envoyé vous permettant de créer un nouveau mot de passe.",
"copyCodeInstruction": "Copiez le code et recopiez le dans votre application :",
"pageExpiredTitle": "La page a expiré",
"pageExpiredMsg1": "Pour recommencer le processus d''authentification",
"pageExpiredMsg2": "Pour continuer le processus d''authentification",
"pageExpiredMsg1": "Pour recommencer le processus d'authentification",
"pageExpiredMsg2": "Pour continuer le processus d'authentification",
"personalInfo": "Information personnelle :",
"role_admin": "Administrateur",
"role_realm-admin": "Administrateur du domaine",
@ -1263,24 +1263,24 @@ export const messages= {
"role_view-applications": "Voir les applications",
"role_view-clients": "Voir les clients",
"role_view-events": "Voir les événements",
"role_view-identity-providers": "Voir les fournisseurs d''identité",
"role_view-identity-providers": "Voir les fournisseurs d'identité",
"role_manage-realm": "Gérer le domaine",
"role_manage-users": "Gérer les utilisateurs",
"role_manage-applications": "Gérer les applications",
"role_manage-identity-providers": "Gérer les fournisseurs d''identité",
"role_manage-identity-providers": "Gérer les fournisseurs d'identité",
"role_manage-clients": "Gérer les clients",
"role_manage-events": "Gérer les événements",
"role_view-profile": "Voir le profil",
"role_manage-account": "Gérer le compte",
"role_manage-account-links": "Gérer les liens de compte",
"role_read-token": "Lire le jeton d''authentification",
"role_read-token": "Lire le jeton d'authentification",
"role_offline-access": "Accès hors-ligne",
"client_account": "Compte",
"client_security-admin-console": "Console d''administration de la sécurité",
"client_security-admin-console": "Console d'administration de la sécurité",
"client_admin-cli": "Admin CLI",
"client_realm-management": "Gestion du domaine",
"client_broker": "Broker",
"invalidUserMessage": "Nom d''utilisateur ou mot de passe invalide.",
"invalidUserMessage": "Nom d'utilisateur ou mot de passe invalide.",
"invalidEmailMessage": "Courriel invalide.",
"accountDisabledMessage": "Compte désactivé, contactez votre administrateur.",
"accountTemporarilyDisabledMessage": "Ce compte est temporairement désactivé, contactez votre administrateur ou bien réessayez plus tard.",
@ -1291,31 +1291,31 @@ export const messages= {
"missingFirstNameMessage": "Veuillez entrer votre prénom.",
"missingLastNameMessage": "Veuillez entrer votre nom.",
"missingEmailMessage": "Veuillez entrer votre courriel.",
"missingUsernameMessage": "Veuillez entrer votre nom d''utilisateur.",
"missingUsernameMessage": "Veuillez entrer votre nom d'utilisateur.",
"missingPasswordMessage": "Veuillez entrer votre mot de passe.",
"missingTotpMessage": "Veuillez entrer votre code d''authentification.",
"missingTotpMessage": "Veuillez entrer votre code d'authentification.",
"notMatchPasswordMessage": "Les mots de passe ne sont pas identiques.",
"invalidPasswordExistingMessage": "Mot de passe existant invalide.",
"invalidPasswordBlacklistedMessage": "Mot de passe invalide : ce mot de passe est blacklisté.",
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
"invalidTotpMessage": "Le code d''authentification est invalide.",
"usernameExistsMessage": "Le nom d''utilisateur existe déjà.",
"invalidTotpMessage": "Le code d'authentification est invalide.",
"usernameExistsMessage": "Le nom d'utilisateur existe déjà.",
"emailExistsMessage": "Le courriel existe déjà.",
"federatedIdentityExistsMessage": "L''utilisateur avec {0} {1} existe déjà. Veuillez accéder à au gestionnaire de compte pour lier le compte.",
"federatedIdentityExistsMessage": "L'utilisateur avec {0} {1} existe déjà. Veuillez accéder à au gestionnaire de compte pour lier le compte.",
"federatedIdentityEmailExistsMessage": "Cet utilisateur avec ce courriel existe déjà. Veuillez vous connecter au gestionnaire de compte pour lier le compte.",
"confirmLinkIdpTitle": "Ce compte existe déjà",
"federatedIdentityConfirmLinkMessage": "L''utilisateur {0} {1} existe déjà. Que souhaitez-vous faire ?",
"federatedIdentityConfirmLinkMessage": "L'utilisateur {0} {1} existe déjà. Que souhaitez-vous faire ?",
"federatedIdentityConfirmReauthenticateMessage": "Identifiez vous afin de lier votre compte avec {0}",
"confirmLinkIdpReviewProfile": "Vérifiez vos informations de profil",
"confirmLinkIdpContinue": "Souhaitez-vous lier {0} à votre compte existant",
"configureTotpMessage": "Vous devez configurer l''authentification par mobile pour activer votre compte.",
"configureTotpMessage": "Vous devez configurer l'authentification par mobile pour activer votre compte.",
"updateProfileMessage": "Vous devez mettre à jour votre profil pour activer votre compte.",
"updatePasswordMessage": "Vous devez changer votre mot de passe pour activer votre compte.",
"resetPasswordMessage": "Vous devez changer votre mot de passe.",
"verifyEmailMessage": "Vous devez vérifier votre courriel pour activer votre compte.",
"linkIdpMessage": "Vous devez vérifier votre courriel pour lier votre compte avec {0}.",
"emailSentMessage": "Vous devriez recevoir rapidement un courriel avec de plus amples instructions.",
"emailSendErrorMessage": "Erreur lors de l''envoi du courriel, veuillez essayer plus tard.",
"emailSendErrorMessage": "Erreur lors de l'envoi du courriel, veuillez essayer plus tard.",
"accountUpdatedMessage": "Votre compte a été mis à jour.",
"accountPasswordUpdatedMessage": "Votre mot de passe a été mis à jour.",
"noAccessMessage": "Aucun accès",
@ -1324,57 +1324,57 @@ export const messages= {
"invalidPasswordMinLowerCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en minuscule.",
"invalidPasswordMinUpperCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en majuscule.",
"invalidPasswordMinSpecialCharsMessage": "Mot de passe invalide : doit contenir au moins {0} caractère(s) spéciaux.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide : ne doit pas être identique au nom d''utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide : ne valide pas l''expression rationnelle.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide : ne doit pas être identique au nom d'utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide : ne valide pas l'expression rationnelle.",
"invalidPasswordHistoryMessage": "Mot de passe invalide : ne doit pas être égal aux {0} derniers mots de passe.",
"invalidPasswordGenericMessage": "Mot de passe invalide : le nouveau mot de passe ne répond pas à la politique de mot de passe.",
"failedToProcessResponseMessage": "Erreur lors du traitement de la réponse",
"httpsRequiredMessage": "Le protocole HTTPS est requis",
"realmNotEnabledMessage": "Le domaine n''est pas activé",
"realmNotEnabledMessage": "Le domaine n'est pas activé",
"invalidRequestMessage": "Requête invalide",
"failedLogout": "La déconnexion a échouée",
"unknownLoginRequesterMessage": "Compte inconnu du demandeur",
"loginRequesterNotEnabledMessage": "La connexion du demandeur n''est pas active",
"loginRequesterNotEnabledMessage": "La connexion du demandeur n'est pas active",
"bearerOnlyMessage": "Les applications Bearer-only ne sont pas autorisées à initier la connexion par navigateur.",
"standardFlowDisabledMessage": "Le client n''est pas autorisé à initier une connexion avec le navigateur avec ce response_type. Le flux standard est désactivé pour le client.",
"implicitFlowDisabledMessage": "Le client n''est pas autorisé à initier une connexion avec le navigateur avec ce response_type. Le flux implicite est désactivé pour le client.",
"invalidRedirectUriMessage": "L''URI de redirection est invalide",
"standardFlowDisabledMessage": "Le client n'est pas autorisé à initier une connexion avec le navigateur avec ce response_type. Le flux standard est désactivé pour le client.",
"implicitFlowDisabledMessage": "Le client n'est pas autorisé à initier une connexion avec le navigateur avec ce response_type. Le flux implicite est désactivé pour le client.",
"invalidRedirectUriMessage": "L'URI de redirection est invalide",
"unsupportedNameIdFormatMessage": "NameIDFormat non supporté",
"invalidRequesterMessage": "Demandeur invalide",
"registrationNotAllowedMessage": "L''enregistrement n''est pas autorisé",
"resetCredentialNotAllowedMessage": "La remise à zéro n''est pas autorisée",
"permissionNotApprovedMessage": "La permission n''est pas approuvée.",
"noRelayStateInResponseMessage": "Aucun état de relais dans la réponse du fournisseur d''identité.",
"registrationNotAllowedMessage": "L'enregistrement n'est pas autorisé",
"resetCredentialNotAllowedMessage": "La remise à zéro n'est pas autorisée",
"permissionNotApprovedMessage": "La permission n'est pas approuvée.",
"noRelayStateInResponseMessage": "Aucun état de relais dans la réponse du fournisseur d'identité.",
"insufficientPermissionMessage": "Permissions insuffisantes pour lier les identités.",
"couldNotProceedWithAuthenticationRequestMessage": "Impossible de continuer avec la requête d''authentification vers le fournisseur d''identité.",
"couldNotObtainTokenMessage": "Impossible de récupérer le jeton du fournisseur d''identité.",
"unexpectedErrorRetrievingTokenMessage": "Erreur inattendue lors de la récupération du jeton provenant du fournisseur d''identité.",
"unexpectedErrorHandlingResponseMessage": "Erreur inattendue lors du traitement de la réponse provenant du fournisseur d''identité.",
"identityProviderAuthenticationFailedMessage": "L''authentification a échouée. Impossible de s''authentifier avec le fournisseur d''identité.",
"couldNotSendAuthenticationRequestMessage": "Impossible d''envoyer la requête d''authentification vers le fournisseur d''identité.",
"unexpectedErrorHandlingRequestMessage": "Erreur inattendue lors du traitement de la requête vers le fournisseur d''identité.",
"invalidAccessCodeMessage": "Code d''accès invalide.",
"sessionNotActiveMessage": "La session n''est pas active.",
"couldNotProceedWithAuthenticationRequestMessage": "Impossible de continuer avec la requête d'authentification vers le fournisseur d'identité.",
"couldNotObtainTokenMessage": "Impossible de récupérer le jeton du fournisseur d'identité.",
"unexpectedErrorRetrievingTokenMessage": "Erreur inattendue lors de la récupération du jeton provenant du fournisseur d'identité.",
"unexpectedErrorHandlingResponseMessage": "Erreur inattendue lors du traitement de la réponse provenant du fournisseur d'identité.",
"identityProviderAuthenticationFailedMessage": "L'authentification a échouée. Impossible de s'authentifier avec le fournisseur d'identité.",
"couldNotSendAuthenticationRequestMessage": "Impossible d'envoyer la requête d'authentification vers le fournisseur d'identité.",
"unexpectedErrorHandlingRequestMessage": "Erreur inattendue lors du traitement de la requête vers le fournisseur d'identité.",
"invalidAccessCodeMessage": "Code d'accès invalide.",
"sessionNotActiveMessage": "La session n'est pas active.",
"invalidCodeMessage": "Une erreur est survenue, veuillez vous reconnecter à votre application.",
"identityProviderUnexpectedErrorMessage": "Erreur inattendue lors de l''authentification avec fournisseur d''identité.",
"identityProviderNotFoundMessage": "Impossible de trouver le fournisseur d''identité avec cet identifiant.",
"identityProviderUnexpectedErrorMessage": "Erreur inattendue lors de l'authentification avec fournisseur d'identité.",
"identityProviderNotFoundMessage": "Impossible de trouver le fournisseur d'identité avec cet identifiant.",
"identityProviderLinkSuccess": "Votre compte a été correctement lié avec {0} compte {1} .",
"staleCodeMessage": "Cette page n''est plus valide, merci de retourner à votre application et de vous connecter à nouveau.",
"realmSupportsNoCredentialsMessage": "Ce domaine ne supporte aucun type d''accréditation.",
"identityProviderNotUniqueMessage": "Ce domaine autorise plusieurs fournisseurs d''identité. Impossible de déterminer le fournisseur d''identité avec lequel s''authentifier.",
"staleCodeMessage": "Cette page n'est plus valide, merci de retourner à votre application et de vous connecter à nouveau.",
"realmSupportsNoCredentialsMessage": "Ce domaine ne supporte aucun type d'accréditation.",
"identityProviderNotUniqueMessage": "Ce domaine autorise plusieurs fournisseurs d'identité. Impossible de déterminer le fournisseur d'identité avec lequel s'authentifier.",
"emailVerifiedMessage": "Votre courriel a été vérifié.",
"staleEmailVerificationLink": "Le lien que vous avez cliqué est périmé et n''est plus valide. Peut-être avez vous déjà vérifié votre mot de passe ?",
"identityProviderAlreadyLinkedMessage": "L''identité fédérée retournée par {0} est déjà liée à un autre utilisateur.",
"confirmAccountLinking": "Confirmez la liaison du compte {0} du fournisseur d''entité {1} avec votre compte.",
"confirmEmailAddressVerification": "Confirmez la validité de l''adresse courriel {0}.",
"staleEmailVerificationLink": "Le lien que vous avez cliqué est périmé et n'est plus valide. Peut-être avez vous déjà vérifié votre mot de passe ?",
"identityProviderAlreadyLinkedMessage": "L'identité fédérée retournée par {0} est déjà liée à un autre utilisateur.",
"confirmAccountLinking": "Confirmez la liaison du compte {0} du fournisseur d'entité {1} avec votre compte.",
"confirmEmailAddressVerification": "Confirmez la validité de l'adresse courriel {0}.",
"confirmExecutionOfActions": "Suivez les instructions suivantes",
"backToApplication": "&laquo; Revenir à l''application",
"backToApplication": "&laquo; Revenir à l'application",
"missingParameterMessage": "Paramètres manquants : {0}",
"clientNotFoundMessage": "Client inconnu.",
"clientDisabledMessage": "Client désactivé.",
"invalidParameterMessage": "Paramètre invalide : {0}",
"alreadyLoggedIn": "Vous êtes déjà connecté.",
"differentUserAuthenticated": "Vous êtes déjà authentifié avec un autre utilisateur ''{0}'' dans cette session. Merci de vous déconnecter.",
"differentUserAuthenticated": "Vous êtes déjà authentifié avec un autre utilisateur '{0}' dans cette session. Merci de vous déconnecter.",
"proceedWithAction": "&raquo; Cliquez ici",
"requiredAction.CONFIGURE_TOTP": "Configurer OTP",
"requiredAction.terms_and_conditions": "Termes et conditions",
@ -1385,7 +1385,7 @@ export const messages= {
"clientCertificate": "X509 certificat client:",
"noCertificate": "[Pas de certificat]",
"pageNotFound": "Page non trouvée",
"internalServerError": "Une erreur interne du serveur s''est produite"
"internalServerError": "Une erreur interne du serveur s'est produite"
},
"it": {
"doLogIn": "Accedi",
@ -1406,8 +1406,8 @@ export const messages= {
"doTryAnotherWay": "Prova in un altro modo",
"kerberosNotConfigured": "Kerberos non configurato",
"kerberosNotConfiguredTitle": "Kerberos non configurato",
"bypassKerberosDetail": "Non sei connesso via Kerberos o il tuo browser non supporta l''autenticazione a Kerberos. Fai clic su Continua per accedere in modo alternativo.",
"kerberosNotSetUp": "Kerberos non è configurato. Non puoi effettuare l''accesso.",
"bypassKerberosDetail": "Non sei connesso via Kerberos o il tuo browser non supporta l'autenticazione a Kerberos. Fai clic su Continua per accedere in modo alternativo.",
"kerberosNotSetUp": "Kerberos non è configurato. Non puoi effettuare l'accesso.",
"registerTitle": "Registrati",
"loginTitle": "Accedi a {0}",
"loginTitleHtml": "{0}",
@ -1422,7 +1422,7 @@ export const messages= {
"oauthGrantTitleHtml": "{0}",
"errorTitle": "Siamo spiacenti…",
"errorTitleHtml": "Siamo <strong>spiacenti</strong>...",
"emailVerifyTitle": "Verifica l''email",
"emailVerifyTitle": "Verifica l'email",
"emailForgotTitle": "Password dimenticata?",
"updatePasswordTitle": "Aggiorna password",
"codeSuccessTitle": "Codice di successo",
@ -1471,11 +1471,11 @@ export const messages= {
"restartLoginTooltip": "Riavvia login",
"loginTotpIntro": "Devi impostare un generatore di OTP (password temporanea valida una volta sola) per accedere a questo account",
"loginTotpStep1": "Installa una delle seguenti applicazioni sul tuo dispositivo mobile",
"loginTotpStep2": "Apri l''applicazione e scansiona il codice QR",
"loginTotpStep3": "Scrivi il codice monouso fornito dall''applicazione e premi Invia per completare il setup",
"loginTotpStep2": "Apri l'applicazione e scansiona il codice QR",
"loginTotpStep3": "Scrivi il codice monouso fornito dall'applicazione e premi Invia per completare il setup",
"loginTotpStep3DeviceName": "Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione.",
"loginTotpManualStep2": "Apri l''applicazione e scrivi la chiave",
"loginTotpManualStep3": "Usa le seguenti impostazioni se l''applicazione lo consente",
"loginTotpManualStep2": "Apri l'applicazione e scrivi la chiave",
"loginTotpManualStep3": "Usa le seguenti impostazioni se l'applicazione lo consente",
"loginTotpUnableToScan": "Non riesci a scansionare il codice QR?",
"loginTotpScanBarcode": "Vuoi scansionare il codice QR?",
"loginCredential": "Credenziali",
@ -1486,7 +1486,7 @@ export const messages= {
"loginTotpInterval": "Intervallo",
"loginTotpCounter": "Contatore",
"loginTotpDeviceName": "Nome del dispositivo di autenticazione",
"loginTotp.totp": "Basato sull''ora",
"loginTotp.totp": "Basato sull'ora",
"loginTotp.hotp": "Basato sul contatore",
"loginChooseAuthenticator": "Seleziona il tuo metodo di autenticazione",
"oauthGrantRequest": "Vuoi assegnare questi privilegi di accesso?",
@ -1495,13 +1495,13 @@ export const messages= {
"emailVerifyInstruction2": "Non hai ricevuto un codice di verifica nella tua email?",
"emailVerifyInstruction3": "per rinviare la email.",
"emailLinkIdpTitle": "Collega {0}",
"emailLinkIdp1": "Ti è stata inviata una email con le istruzioni per collegare l''account {0} {1} con il tuo account {2}.",
"emailLinkIdp1": "Ti è stata inviata una email con le istruzioni per collegare l'account {0} {1} con il tuo account {2}.",
"emailLinkIdp2": "Non hai ricevuto un codice di verifica nella tua email?",
"emailLinkIdp3": "Per rinviare la email.",
"emailLinkIdp4": "Se hai già verificato l''indirizzo email in un altro browser",
"emailLinkIdp4": "Se hai già verificato l'indirizzo email in un altro browser",
"emailLinkIdp5": "per continuare.",
"backToLogin": "&laquo; Torna al Login",
"emailInstruction": "Inserisci la tua username o l''indirizzo email e ti manderemo le istruzioni per creare una nuova password.",
"emailInstruction": "Inserisci la tua username o l'indirizzo email e ti manderemo le istruzioni per creare una nuova password.",
"copyCodeInstruction": "Copia questo codice e incollalo nella tua applicazione:",
"pageExpiredTitle": "La pagina è scaduta",
"pageExpiredMsg1": "Per ripetere il login",
@ -1525,7 +1525,7 @@ export const messages= {
"role_manage-events": "Gestisci eventi",
"role_view-profile": "Visualizza profilo",
"role_manage-account": "Gestisci account",
"role_manage-account-links": "Gestisci i link per l''account",
"role_manage-account-links": "Gestisci i link per l'account",
"role_read-token": "Leggi il token",
"role_offline-access": "Accesso offline",
"client_account": "Account",
@ -1540,16 +1540,16 @@ export const messages= {
"invalidUsernameOrEmailMessage": "Username o email non validi.",
"invalidPasswordMessage": "Password non valida.",
"invalidEmailMessage": "Indirizzo email non valido.",
"accountDisabledMessage": "L''account è disabilitato, contatta il tuo amministratore.",
"accountTemporarilyDisabledMessage": "L''account è temporaneamente disabilitato; contatta il tuo amministratore o prova più tardi.",
"accountDisabledMessage": "L'account è disabilitato, contatta il tuo amministratore.",
"accountTemporarilyDisabledMessage": "L'account è temporaneamente disabilitato; contatta il tuo amministratore o prova più tardi.",
"expiredCodeMessage": "Login scaduto. Riprovare.",
"expiredActionMessage": "Azione scaduta. Continuare adesso con in login.",
"expiredActionTokenNoSessionMessage": "Azione scaduta.",
"expiredActionTokenSessionExistsMessage": "Azione scaduta. Ricominciare.",
"missingFirstNameMessage": "Inserisci il nome.",
"missingLastNameMessage": "Inserisci il cognome.",
"missingEmailMessage": "Inserisci l''email.",
"missingUsernameMessage": "Inserisci l''username.",
"missingEmailMessage": "Inserisci l'email.",
"missingUsernameMessage": "Inserisci l'username.",
"missingPasswordMessage": "Inserisci la password.",
"missingTotpMessage": "Inserisci il codice di autenticazione.",
"missingTotpDeviceNameMessage": "Inserisci il nome del dispositivo di autenticazione.",
@ -1560,12 +1560,12 @@ export const messages= {
"invalidTotpMessage": "Codice di autenticazione non valido.",
"usernameExistsMessage": "Username già esistente.",
"emailExistsMessage": "Email già esistente.",
"federatedIdentityExistsMessage": "L''utente con {0} {1} esiste già. Effettua il login nella gestione account per associare l''account.",
"federatedIdentityExistsMessage": "L'utente con {0} {1} esiste già. Effettua il login nella gestione account per associare l'account.",
"confirmLinkIdpTitle": "Account già esistente",
"federatedIdentityConfirmLinkMessage": "L''utente con {0} {1} esiste già. Come vuoi procedere?",
"federatedIdentityConfirmLinkMessage": "L'utente con {0} {1} esiste già. Come vuoi procedere?",
"federatedIdentityConfirmReauthenticateMessage": "Autenticati per associare il tuo account con {0}",
"confirmLinkIdpReviewProfile": "Rivedi profilo",
"confirmLinkIdpContinue": "Aggiungi all''account esistente",
"confirmLinkIdpContinue": "Aggiungi all'account esistente",
"configureTotpMessage": "Devi impostare un autenticatore per attivare il tuo account.",
"updateProfileMessage": "Devi aggiornare il tuo profilo utente per attivare il tuo account.",
"updatePasswordMessage": "Devi cambiare la password per attivare il tuo account.",
@ -1590,7 +1590,7 @@ export const messages= {
"invalidPasswordRegexPatternMessage": "Password non valida: fallito il match con una o più espressioni regolari.",
"invalidPasswordHistoryMessage": "Password non valida: non deve essere uguale ad una delle ultime {0} password.",
"invalidPasswordGenericMessage": "Password non valida: la nuova password non rispetta le indicazioni previste.",
"failedToProcessResponseMessage": "Fallimento nell''elaborazione della risposta",
"failedToProcessResponseMessage": "Fallimento nell'elaborazione della risposta",
"httpsRequiredMessage": "HTTPS richiesto",
"realmNotEnabledMessage": "Realm non abilitato",
"invalidRequestMessage": "Richiesta non valida",
@ -1606,46 +1606,46 @@ export const messages= {
"registrationNotAllowedMessage": "Registrazione non permessa",
"resetCredentialNotAllowedMessage": "Reimpostazione della credenziale non permessa",
"permissionNotApprovedMessage": "Permesso non approvato.",
"noRelayStateInResponseMessage": "Nessun relay state in risposta dall''identity provider.",
"noRelayStateInResponseMessage": "Nessun relay state in risposta dall'identity provider.",
"insufficientPermissionMessage": "Permessi insufficienti per associare le identità.",
"couldNotProceedWithAuthenticationRequestMessage": "Impossibile procedere con la richiesta di autenticazione all''identity provider",
"couldNotObtainTokenMessage": "Non posso ottenere un token dall''identity provider.",
"unexpectedErrorRetrievingTokenMessage": "Errore inaspettato nel recupero del token dall''identity provider.",
"unexpectedErrorHandlingResponseMessage": "Errore inaspettato nella gestione della risposta dall''identity provider.",
"identityProviderAuthenticationFailedMessage": "Autenticazione fallita. Non posso effettuare l''autenticazione con l''identity provider.",
"couldNotSendAuthenticationRequestMessage": "Impossibile inviare la richiesta di autenticazione all''identity provider.",
"unexpectedErrorHandlingRequestMessage": "Errore inaspettato nella gestione della richiesta di autenticazione all''identity provider.",
"couldNotProceedWithAuthenticationRequestMessage": "Impossibile procedere con la richiesta di autenticazione all'identity provider",
"couldNotObtainTokenMessage": "Non posso ottenere un token dall'identity provider.",
"unexpectedErrorRetrievingTokenMessage": "Errore inaspettato nel recupero del token dall'identity provider.",
"unexpectedErrorHandlingResponseMessage": "Errore inaspettato nella gestione della risposta dall'identity provider.",
"identityProviderAuthenticationFailedMessage": "Autenticazione fallita. Non posso effettuare l'autenticazione con l'identity provider.",
"couldNotSendAuthenticationRequestMessage": "Impossibile inviare la richiesta di autenticazione all'identity provider.",
"unexpectedErrorHandlingRequestMessage": "Errore inaspettato nella gestione della richiesta di autenticazione all'identity provider.",
"invalidAccessCodeMessage": "Codice di accesso non valido.",
"sessionNotActiveMessage": "Sessione non attiva.",
"invalidCodeMessage": "Si è verificato un errore, effettua di nuovo il login nella tua applicazione.",
"identityProviderUnexpectedErrorMessage": "Errore imprevisto durante l''autenticazione con identity provider",
"identityProviderNotFoundMessage": "Non posso trovare un identity provider con l''identificativo.",
"identityProviderUnexpectedErrorMessage": "Errore imprevisto durante l'autenticazione con identity provider",
"identityProviderNotFoundMessage": "Non posso trovare un identity provider con l'identificativo.",
"identityProviderLinkSuccess": "Hai verificato con successo la tua email. Torna al tuo browser iniziale e continua da lì con il login.",
"staleCodeMessage": "Questa pagina non è più valida, torna alla tua applicazione ed effettua nuovamente l''accesso",
"staleCodeMessage": "Questa pagina non è più valida, torna alla tua applicazione ed effettua nuovamente l'accesso",
"realmSupportsNoCredentialsMessage": "Il realm non supporta nessun tipo di credenziali.",
"credentialSetupRequired": "Impossibile effettuare il login, è richiesto il setup delle credenziali.",
"identityProviderNotUniqueMessage": "Il realm supporta più di un identity provider. Impossibile determinare quale identity provider deve essere utilizzato per autenticarti.",
"emailVerifiedMessage": "Il tuo indirizzo email è stato verificato.",
"staleEmailVerificationLink": "Il link che hai cliccato è un link scaduto e non è più valido. Forse hai già verificato la tua email?",
"identityProviderAlreadyLinkedMessage": "L''identità federata restituita dall''identity provider {0} è già associata ad un altro utente.",
"confirmAccountLinking": "Conferma il collegamento per l''account {0} dell''identity provider {1} con il tuo account.",
"confirmEmailAddressVerification": "Conferma la validità dell''indirizzo email {0}.",
"identityProviderAlreadyLinkedMessage": "L'identità federata restituita dall'identity provider {0} è già associata ad un altro utente.",
"confirmAccountLinking": "Conferma il collegamento per l'account {0} dell'identity provider {1} con il tuo account.",
"confirmEmailAddressVerification": "Conferma la validità dell'indirizzo email {0}.",
"confirmExecutionOfActions": "Esegui la/le seguenti azione/i",
"locale_it": "Italiano",
"backToApplication": "&laquo; Torna all''applicazione",
"backToApplication": "&laquo; Torna all'applicazione",
"missingParameterMessage": "Parametri mancanti: {0}",
"clientNotFoundMessage": "Client non trovato.",
"clientDisabledMessage": "Client disabilitato.",
"invalidParameterMessage": "Parametro non valido: {0}",
"alreadyLoggedIn": "Sei già connesso.",
"differentUserAuthenticated": "Se già autenticato con l''utente ''{0}'' in questa sessione. Per favore, fai prima il logout.",
"brokerLinkingSessionExpired": "È stato richiesta un''associazione a un account broker, ma la sessione corrente non è più valida.",
"differentUserAuthenticated": "Se già autenticato con l'utente '{0}' in questa sessione. Per favore, fai prima il logout.",
"brokerLinkingSessionExpired": "È stato richiesta un'associazione a un account broker, ma la sessione corrente non è più valida.",
"proceedWithAction": "&raquo; Clicca qui per continuare",
"requiredAction.CONFIGURE_TOTP": "Configura OTP",
"requiredAction.terms_and_conditions": "Termini e condizioni",
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
"requiredAction.UPDATE_PROFILE": "Aggiornamento profilo",
"requiredAction.VERIFY_EMAIL": "Verifica dell''indirizzo email",
"requiredAction.VERIFY_EMAIL": "Verifica dell'indirizzo email",
"doX509Login": "Sarai connesso come:",
"clientCertificate": "Certificato client X509:",
"noCertificate": "[Nessun certificato]",
@ -1656,20 +1656,20 @@ export const messages= {
"console-otp": "One-time password:",
"console-new-password": "Nuova password:",
"console-confirm-password": "Conferma password:",
"console-update-password": "È richiesto l''aggiornamento della tua password.",
"console-update-password": "È richiesto l'aggiornamento della tua password.",
"console-verify-email": "Devi verificare il tuo indirizzo email. È stata inviata una email a {0} che contiene un codice di verifica. Per favore inserisci il codice nella casella di testo seguente.",
"console-email-code": "Codice email:",
"console-accept-terms": "Accetti i termini? [y/n]:",
"console-accept": "y",
"openshift.scope.user_info": "Informazioni utente",
"openshift.scope.user_check-access": "Informazioni di accesso per l''utente",
"openshift.scope.user_check-access": "Informazioni di accesso per l'utente",
"openshift.scope.user_full": "Accesso completo",
"openshift.scope.list-projects": "Elenca i progetti",
"saml.post-form.title": "Reindirizzamento per l''autenticazione",
"saml.post-form.title": "Reindirizzamento per l'autenticazione",
"saml.post-form.message": "Reindirizzamento, attendere per favore.",
"saml.post-form.js-disabled": "JavaScript è disabilitato. È fortemente consigliato abilitarlo. Clicca sul bottone seguente per continuare.",
"otp-display-name": "Applicazione di autenticazione",
"otp-help-text": "Inserire un codice di verifica fornito dall''applicazione di autenticazione.",
"otp-help-text": "Inserire un codice di verifica fornito dall'applicazione di autenticazione.",
"password-display-name": "Password",
"password-help-text": "Accedi inserendo la tua password.",
"auth-username-form-display-name": "Username",
@ -1679,7 +1679,7 @@ export const messages= {
"webauthn-display-name": "Chiave di sicurezza",
"webauthn-help-text": "Utilizza la tua chiave di sicurezza per accedere.",
"webauthn-passwordless-display-name": "Chiave di sicurezza",
"webauthn-passwordless-help-text": "Utilizza la tua chiave di sicurezza per l''accesso senza password.",
"webauthn-passwordless-help-text": "Utilizza la tua chiave di sicurezza per l'accesso senza password.",
"webauthn-login-title": "Login con chiave di sicurezza",
"webauthn-registration-title": "Registrazione chiave di sicurezza",
"webauthn-available-authenticators": "Autenticatori disponibili",
@ -1687,7 +1687,7 @@ export const messages= {
"webauthn-error-registration": "Impossibile registrare la tua chiave di sicurezza.",
"webauthn-error-api-get": "Autenticazione con la chiave di sicurezza fallita.",
"webauthn-error-different-user": "Il primo utente autenticato non è quello autenticato tramite la chiave di sicurezza.",
"webauthn-error-auth-verification": "Il risultato dell''autenticazione con la chiave di sicurezza non è valido.",
"webauthn-error-auth-verification": "Il risultato dell'autenticazione con la chiave di sicurezza non è valido.",
"webauthn-error-register-verification": "Il risultato della registrazione della chiave di sicurezza non è valido.",
"webauthn-error-user-not-found": "Utente sconosciuto autenticato con la chiave di sicurezza.",
"identity-provider-redirector": "Connettiti con un altro identity provider."
@ -1960,7 +1960,7 @@ export const messages= {
"clientDisabledMessage": "クライアントが無効になっています。",
"invalidParameterMessage": "無効なパラメーター: {0}",
"alreadyLoggedIn": "既にログインしています。",
"differentUserAuthenticated": "すでにこのセッションで異なるユーザー''{0}''として認証されています。まずログアウトしてください。",
"differentUserAuthenticated": "すでにこのセッションで異なるユーザー'{0}'として認証されています。まずログアウトしてください。",
"brokerLinkingSessionExpired": "要求されたブローカー・アカウントのリンクは、現在のセッションでは有効ではありません。",
"proceedWithAction": "&raquo; 続行するにはここをクリックしてください",
"requiredAction.CONFIGURE_TOTP": "OTPの設定",
@ -2920,7 +2920,7 @@ export const messages= {
"clientDisabledMessage": "Klient nieaktywny.",
"invalidParameterMessage": "Nieprawidłowy parametr: {0}",
"alreadyLoggedIn": "Jesteś już zalogowany.",
"differentUserAuthenticated": "Jesteś już uwierzytelniona/y jako inny użytkownik ''{0}'' w tej sesji. Najpierw się wyloguj.",
"differentUserAuthenticated": "Jesteś już uwierzytelniona/y jako inny użytkownik '{0}' w tej sesji. Najpierw się wyloguj.",
"brokerLinkingSessionExpired": "Żądano łączenia kont brokera, ale bieżąca sesja już jest nieważna.",
"proceedWithAction": "&raquo; kliknij tutaj, aby przejść",
"requiredAction.CONFIGURE_TOTP": "Skonfiguruj OTP",
@ -3211,7 +3211,7 @@ export const messages= {
"clientDisabledMessage": "Cliente desativado.",
"invalidParameterMessage": "Parâmentro inválido: {0}",
"alreadyLoggedIn": "Você já está logado.",
"differentUserAuthenticated": "Você já está autenticado como usuário diferente ''{0}'' nesta sessão. Por favor, saia primeiro.",
"differentUserAuthenticated": "Você já está autenticado como usuário diferente '{0}' nesta sessão. Por favor, saia primeiro.",
"brokerLinkingSessionExpired": "Vinculação de conta do provedor de identidade solicitada, mas a sessão atual não é mais válida.",
"proceedWithAction": "&raquo; Clique aqui para continuar",
"requiredAction.CONFIGURE_TOTP": "Configurar OTP",
@ -3676,7 +3676,7 @@ export const messages= {
"clientDisabledMessage": "Klient bol zneplatnený.",
"invalidParameterMessage": "Neplatný parameter : {0}",
"alreadyLoggedIn": "Už ste prihlásený.",
"differentUserAuthenticated": "V tejto relácii ste už boli overení ako iný používateľ '' {0} ''. Najskôr sa odhláste.",
"differentUserAuthenticated": "V tejto relácii ste už boli overení ako iný používateľ ' {0} '. Najskôr sa odhláste.",
"brokerLinkingSessionExpired": "Požadované prepojenie s účtom brokera, ale aktuálna relácia už nie je platná.",
"proceedWithAction": "&raquo; Ak chcete pokračovať, kliknite sem",
"requiredAction.CONFIGURE_TOTP": "Konfigurácia OTP",
@ -3895,7 +3895,7 @@ export const messages= {
"doImpersonate": "Kişiselleştir",
"kerberosNotConfigured": "Kerberos Tanımlanmamış",
"kerberosNotConfiguredTitle": "Kerberos Tanımlanmamış",
"bypassKerberosDetail": "Ya Kerberos ile giriş yapmadınız veya tarayıcınız Kerberos giriş için ayarlanmamış. Diğer yollarla giriş yapmak için lütfen devam''a tıklayın",
"bypassKerberosDetail": "Ya Kerberos ile giriş yapmadınız veya tarayıcınız Kerberos giriş için ayarlanmamış. Diğer yollarla giriş yapmak için lütfen devam'a tıklayın",
"kerberosNotSetUp": "Kerberos kurulmadı. Giriş yapamazsın.",
"registerTitle": "Kayıt ol",
"loginTitle": "{0} adresinde oturum açın",
@ -3960,7 +3960,7 @@ export const messages= {
"loginTotpIntro": "Bu hesaba erişmek için bir Tek Kullanımlık Şifre oluşturmalısınız.",
"loginTotpStep1": "Cep telefonunuzda aşağıdaki uygulamalardan birini yükleyin",
"loginTotpStep2": "Uygulamayıın ve barkodu tarayın",
"loginTotpStep3": "Uygulama tarafından sağlanan tek seferlik kodu girin ve kurulumu tamamlamak için Gönder''i tıklayın.",
"loginTotpStep3": "Uygulama tarafından sağlanan tek seferlik kodu girin ve kurulumu tamamlamak için Gönder'i tıklayın.",
"loginTotpManualStep2": "Uygulamayıın ve anahtarı girin",
"loginTotpManualStep3": "Uygulama bunları ayarlamaya izin veriyorsa aşağıdaki yapılandırma değerlerini kullanın.",
"loginTotpUnableToScan": "Taranamıyor?",
@ -3984,7 +3984,7 @@ export const messages= {
"emailLinkIdp3": "e-postayı yeniden göndermek için.",
"emailLinkIdp4": "E-postayı farklı tarayıcıda zaten doğruladıysanız",
"emailLinkIdp5": "devam etmek.",
"backToLogin": "&laquo; Giriş''e geri dön",
"backToLogin": "&laquo; Giriş'e geri dön",
"emailInstruction": "Kullanıcı adınızı veya e-posta adresinizi girin ve yeni bir şifre oluşturmaya ilişkin talimatları size göndereceğiz.",
"copyCodeInstruction": "Lütfen bu kodu kopyalayın ve uygulamanıza yapıştırın:",
"pageExpiredTitle": "Sayfanın Süresi Doldu",
@ -4043,7 +4043,7 @@ export const messages= {
"federatedIdentityConfirmLinkMessage": "{0} {1} kullanıcı zaten var. Nasıl devam etmek istersin?",
"confirmLinkIdpReviewProfile": "Profili gözden geçir",
"confirmLinkIdpContinue": "Mevcut hesaba ekle",
"configureTotpMessage": "Hesabınızı etkinleştirmek için Mobil Kimlik Doğrulama''yı ayarlamanız gerekiyor.",
"configureTotpMessage": "Hesabınızı etkinleştirmek için Mobil Kimlik Doğrulama'yı ayarlamanız gerekiyor.",
"updateProfileMessage": "Hesabınızı etkinleştirmek için kullanıcı profilinizi güncellemeniz gerekiyor.",
"updatePasswordMessage": "Hesabınızı etkinleştirmek için şifrenizi değiştirmeniz gerekiyor.",
"resetPasswordMessage": "Şifreni değiştirmelisin.",
@ -4077,7 +4077,7 @@ export const messages= {
"bearerOnlyMessage": "Yalnızca taşıyıcı uygulamaları tarayıcı girişini başlatmaya izinli değil",
"standardFlowDisabledMessage": "Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.",
"implicitFlowDisabledMessage": "Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.",
"invalidRedirectUriMessage": "Geçersiz yönlendirme url''i",
"invalidRedirectUriMessage": "Geçersiz yönlendirme url'i",
"unsupportedNameIdFormatMessage": "Desteklenmeyen NameIDFormat",
"invalidRequesterMessage": "Geçersiz istek",
"registrationNotAllowedMessage": "Kayıt yapılamaz",
@ -4131,14 +4131,14 @@ export const messages= {
"clientDisabledMessage": "İstemci engelli.",
"invalidParameterMessage": "Geçersiz Paremetreler: {0}",
"alreadyLoggedIn": "Zaten giriş yaptınız.",
"differentUserAuthenticated": "Bu oturumda zaten farklı kullanıcı '' {0} '' olarak doğrulanmışsınız. Lütfen önce çıkış yapınız.",
"differentUserAuthenticated": "Bu oturumda zaten farklı kullanıcı ' {0} ' olarak doğrulanmışsınız. Lütfen önce çıkış yapınız.",
"brokerLinkingSessionExpired": "İstenen broker hesabı bağlanıyor, ancak mevcut oturum artık geçerli değil.",
"proceedWithAction": "&raquo; Devam etmek için buraya tıklayın",
"requiredAction.CONFIGURE_TOTP": "OTP Ayarla",
"requiredAction.terms_and_conditions": "Şartlar ve Koşullar",
"requiredAction.UPDATE_PASSWORD": "Şifre güncelle",
"requiredAction.UPDATE_PROFILE": "Profili Güncelle",
"requiredAction.VERIFY_EMAIL": "E-mail''i doğrula",
"requiredAction.VERIFY_EMAIL": "E-mail'i doğrula",
"doX509Login": "Olarak giriş yapacaksınız:",
"clientCertificate": "X509 istemci sertifikası:",
"noCertificate": "[Sertifika Yok]",
@ -4360,5 +4360,5 @@ export const messages= {
"invalidParameterMessage": "无效的参数 : {0}",
"alreadyLoggedIn": "您已经登录"
}
} as const;
};
/* spell-checker: enable */

View File

@ -0,0 +1,33 @@
import { kcMessages } from "../generated_kcMessages/login";
import { Evt } from "evt";
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
export const evtTermsUpdated = Evt.asNonPostable(Evt.create<void>());
(["termsText", "doAccept", "doDecline", "termsTitle"] as const).forEach(key =>
objectKeys(kcMessages).forEach(kcLanguage =>
Object.defineProperty(
kcMessages[kcLanguage],
key,
(() => {
let value = key === "termsText" ? "⏳" : kcMessages[kcLanguage][key];
return {
"enumerable": true,
"get": () => value,
"set": (newValue: string) => {
value = newValue;
Evt.asPostable(evtTermsUpdated).post();
}
};
})()
)
)
);
export { kcMessages };

View File

@ -1,13 +1,23 @@
import { createUseGlobalState } from "powerhooks";
import { kcContext } from "../kcContext";
import { kcContext } from "../KcContext";
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
export const { useKcLanguageTag } = createUseGlobalState(
//export const { useKcLanguageTag, evtKcLanguageTag } = createUseGlobalState(
const wrap = createUseGlobalState(
"kcLanguageTag",
() => getBestMatchAmongKcLanguageTag(
kcContext?.locale?.["current" as never] ??
kcContext?.locale?.current ??
navigator.language
),
{ "persistance": "cookies" }
{ "persistance": "cookie" }
);
export const { useKcLanguageTag } = wrap;
export function getEvtKcLanguage() {
return wrap.evtKcLanguageTag;
}

View File

@ -0,0 +1,51 @@
import { useCallback, useReducer } from "react";
import { useKcLanguageTag } from "./useKcLanguageTag";
import { kcMessages, evtTermsUpdated } from "./kcMessages/login";
import type { ReactNode } from "react";
import { useEvt } from "evt/hooks";
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
import ReactMarkdown from "react-markdown";
export type MessageKey = keyof typeof kcMessages["en"];
export function useKcMessage() {
const { kcLanguageTag } = useKcLanguageTag();
const [trigger, forceUpdate] = useReducer((counter: number) => counter + 1, 0);
useEvt(ctx => evtTermsUpdated.attach(ctx, forceUpdate), []);
const msgStr = useCallback(
(key: MessageKey, ...args: (string | undefined)[]): string => {
let str: string = kcMessages[kcLanguageTag as any as "en"][key] ?? kcMessages["en"][key];
args.forEach((arg, i) => {
if (arg === undefined) {
return;
}
str = str.replace(new RegExp(`\\{${i}\\}`, "g"), arg);
});
return str;
},
[kcLanguageTag, trigger]
);
const msg = useCallback<(...args: Parameters<typeof msgStr>) => ReactNode>(
(key, ...args) =>
<ReactMarkdown allowDangerousHtml renderers={key === "termsText" ? undefined : { "paragraph": "span" }}>
{msgStr(key, ...args)}
</ReactMarkdown>,
[msgStr]
);
return { msg, msgStr };
}

View File

@ -1,43 +0,0 @@
import { useKcLanguageTag } from "./useKcLanguageTag";
import { messages } from "./generated_messages/login";
import { useConstCallback } from "powerhooks";
import type { ReactNode } from "react";
import { id } from "evt/tools/typeSafety/id";
export type MessageKey = keyof typeof messages["en"];
export function useKcTranslation() {
const { kcLanguageTag } = useKcLanguageTag();
const tStr = useConstCallback(
(key: MessageKey, ...args: (string | undefined)[]): string => {
let str: string = messages[kcLanguageTag as any as "en"][key] ?? messages["en"][key];
args.forEach((arg, i) => {
if (arg === undefined) {
return;
}
str = str.replace(new RegExp(`\\{${i}\\}`, "g"), arg);
});
return str;
}
);
const t = useConstCallback(
id<(...args: Parameters<typeof tStr>) => ReactNode>(
(key, ...args) =>
<span className={key} dangerouslySetInnerHTML={{ "__html": tStr(key, ...args) }} />
)
);
return { t, tStr };
}

View File

@ -1,10 +1,21 @@
export * from "./kcContext";
export * from "./KcContext";
export * from "./i18n/KcLanguageTag";
export * from "./i18n/useKcLanguageTag";
export * from "./i18n/useKcTranslation";
export * from "./i18n/useKcMessage";
export * from "./i18n/kcMessages/login";
export * from "./components/KcProperties";
export * from "./components/KcProps";
export * from "./components/Login";
export * from "./components/Template";
export * from "./components/KcApp";
export * from "./components/KcApp";
export * from "./components/Info";
export * from "./components/Error";
export * from "./components/LoginResetPassword";
export * from "./components/LoginVerifyEmail";
export * from "./keycloakJsAdapter";
export * from "./tools/assert";
export * as kcContextMocks from "./kcContextMocks";

View File

@ -1,72 +1,182 @@
import { ftlValuesGlobalName } from "../bin/build-keycloak-theme/ftlValuesGlobalName";
import type { generateFtlFilesCodeFactory } from "../bin/build-keycloak-theme/generateFtl";
import type { PageId } from "../bin/build-keycloak-theme/generateFtl";
import { id } from "evt/tools/typeSafety/id";
import type { KcLanguageTag } from "./i18n/KcLanguageTag";
import type { KcLanguageTag } from "./i18n/KcLanguageTag";
import { doExtends } from "evt/tools/typeSafety/doExtends";
import type { MessageKey } from "./i18n/useKcMessage";
import type { LanguageLabel } from "./i18n/KcLanguageTag";
type ExtractAfterStartingWith<Prefix extends string, StrEnum> =
StrEnum extends `${Prefix}${infer U}` ? U : never;
export type KcContext = {
pageBasename: Parameters<ReturnType<typeof generateFtlFilesCodeFactory>["generateFtlFilesCode"]>[0]["pageBasename"];
url: {
loginAction: string;
resourcesPath: string;
resourcesCommonPath: string;
loginRestartFlowUrl: string;
loginResetCredentialsUrl: string;
registrationUrl: string;
};
realm: {
displayName?: string;
displayNameHtml?: string;
internationalizationEnabled: boolean;
password: boolean;
loginWithEmailAllowed: boolean;
registrationEmailAsUsername: boolean;
rememberMe: boolean;
resetPasswordAllowed: boolean;
};
/** Undefined if !realm.internationalizationEnabled */
locale?: {
supported: {
//url: string;
languageTag: KcLanguageTag;
/** Is determined by languageTag. Ex: languageTag === "en" => label === "English"
* or getLanguageLabel(languageTag) === label
*/
//label: LanguageLabel;
}[];
//NOTE: We do not expose this because the language is managed
//client side. We use this value however to set the default.
//current: LanguageLabel;
},
auth?: {
showUsername: boolean;
showResetCredentials: boolean;
showTryAnotherWayLink: boolean;
attemptedUsername?: boolean;
selectedCredential?: string;
};
scripts: string[];
message?: {
type: "success" | "warning" | "error" | "info";
summary: string;
};
isAppInitiatedAction: boolean;
social: {
displayInfo: boolean;
providers?: {
/** Take theses type definition with a grain of salt.
* Some values might be undefined on some pages.
* (ex: url.loginAction is undefined on error.ftl)
*/
export type KcContext =
KcContext.Login | KcContext.Register | KcContext.Info |
KcContext.Error | KcContext.LoginResetPassword | KcContext.LoginVerifyEmail |
KcContext.Terms | KcContext.LoginOtp;
export declare namespace KcContext {
export type Common = {
url: {
loginAction: string;
resourcesPath: string;
resourcesCommonPath: string;
loginRestartFlowUrl: string;
loginUrl: string;
alias: string;
providerId: string;
displayName: string;
}[]
};
realm: {
displayName?: string;
displayNameHtml?: string;
internationalizationEnabled: boolean;
registrationEmailAsUsername: boolean;
};
/** Undefined if !realm.internationalizationEnabled */
locale?: {
supported: {
url: string;
languageTag: KcLanguageTag;
/** Is determined by languageTag. Ex: languageTag === "en" => label === "English"
* or getLanguageLabel(languageTag) === label
*/
//label: LanguageLabel;
}[];
current: LanguageLabel;
},
auth?: {
showUsername: boolean;
showResetCredentials: boolean;
showTryAnotherWayLink: boolean;
attemptedUsername?: string;
};
scripts: string[];
message?: {
type: "success" | "warning" | "error" | "info";
summary: string;
};
isAppInitiatedAction: boolean;
};
usernameEditDisabled: boolean;
login: {
username?: string;
rememberMe: boolean;
export type Login = Common & {
pageId: "login.ftl";
url: {
loginResetCredentialsUrl: string;
registrationUrl: string;
};
realm: {
loginWithEmailAllowed: boolean;
rememberMe: boolean;
password: boolean;
resetPasswordAllowed: boolean;
registrationAllowed: boolean;
};
auth: {
selectedCredential?: string;
};
registrationDisabled: boolean;
login: {
username?: string;
rememberMe: boolean;
};
usernameEditDisabled: boolean;
social: {
displayInfo: boolean;
providers?: {
loginUrl: string;
alias: string;
providerId: string;
displayName: string;
}[]
};
};
registrationDisabled: boolean;
};
export type Register = Common & {
pageId: "register.ftl";
url: {
registrationAction: string;
};
messagesPerField: {
printIfExists<T>(
key:
"userLabel" |
"username" |
"email" |
"firstName" |
"lastName" |
"password" |
"password-confirm",
x: T
): T | undefined;
};
register: {
formData: {
firstName?: string;
displayName?: string;
lastName?: string;
email?: string;
username?: string;
}
};
passwordRequired: boolean;
recaptchaRequired: boolean;
recaptchaSiteKey?: string;
/**
* Defined when you use the keycloak-mail-whitelisting keycloak plugin
* (https://github.com/micedre/keycloak-mail-whitelisting)
*/
authorizedMailDomains?: string[];
};
export type Info = Common & {
pageId: "info.ftl";
messageHeader?: string;
requiredActions?: ExtractAfterStartingWith<"requiredAction.", MessageKey>[];
skipLink: boolean;
pageRedirectUri?: string;
actionUri?: string;
client: {
baseUrl?: string;
}
};
export type Error = Common & {
pageId: "error.ftl";
client?: {
baseUrl?: string;
}
};
export type LoginResetPassword = Common & {
pageId: "login-reset-password.ftl";
realm: {
loginWithEmailAllowed: boolean;
}
};
export type LoginVerifyEmail = Common & {
pageId: "login-verify-email.ftl";
};
export type Terms = Common & {
pageId: "terms.ftl";
};
export type LoginOtp = Common & {
pageId: "login-otp.ftl";
otpLogin: {
userOtpCredentials: { id: string; userLabel: string; }[];
}
};
}
doExtends<KcContext["pageId"], PageId>();
doExtends<PageId, KcContext["pageId"]>();
export const kcContext = id<KcContext | undefined>((window as any)[ftlValuesGlobalName]);

View File

@ -0,0 +1,230 @@
import type { KcContext } from "../KcContext";
import { getEvtKcLanguage } from "../i18n/useKcLanguageTag";
import { getKcLanguageTagLabel } from "../i18n/KcLanguageTag";
//NOTE: Aside because we want to be able to import them from node
import { resourcesCommonPath, resourcesPath } from "./urlResourcesPath";
const kcCommonContext: KcContext.Common = {
"url": {
"loginAction": "#",
"resourcesPath": `${process.env["PUBLIC_URL"]}/${resourcesPath}`,
"resourcesCommonPath": `${process.env["PUBLIC_URL"]}/${resourcesCommonPath}`,
"loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg",
"loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg",
},
"realm": {
"displayName": "myrealm",
"displayNameHtml": "myrealm",
"internationalizationEnabled": true,
"registrationEmailAsUsername": true,
},
"locale": {
"supported": [
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=de",
"languageTag": "de"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=no",
"languageTag": "no"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ru",
"languageTag": "ru"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sv",
"languageTag": "sv"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pt-BR",
"languageTag": "pt-BR"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=lt",
"languageTag": "lt"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=en",
"languageTag": "en"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=it",
"languageTag": "it"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=fr",
"languageTag": "fr"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=zh-CN",
"languageTag": "zh-CN"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=es",
"languageTag": "es"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=cs",
"languageTag": "cs"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ja",
"languageTag": "ja"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sk",
"languageTag": "sk"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pl",
"languageTag": "pl"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ca",
"languageTag": "ca"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=nl",
"languageTag": "nl"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=tr",
"languageTag": "tr"
}
],
"current": null as any
},
"auth": {
"showUsername": false,
"showResetCredentials": false,
"showTryAnotherWayLink": false
},
"scripts": [],
"message": {
"type": "success",
"summary": "This is a test message"
},
"isAppInitiatedAction": false,
};
Object.defineProperty(
kcCommonContext.locale!,
"current",
{
"get": () => getKcLanguageTagLabel(getEvtKcLanguage().state),
"enumerable": true
}
);
export const kcLoginContext: KcContext.Login = {
...kcCommonContext,
"pageId": "login.ftl",
"url": {
...kcCommonContext.url,
"loginResetCredentialsUrl": "/auth/realms/myrealm/login-actions/reset-credentials?client_id=account&tab_id=HoAx28ja4xg",
"registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg"
},
"realm": {
...kcCommonContext.realm,
"loginWithEmailAllowed": true,
"rememberMe": true,
"password": true,
"resetPasswordAllowed": true,
"registrationAllowed": true
},
"auth": kcCommonContext.auth!,
"social": {
"displayInfo": true
},
"usernameEditDisabled": false,
"login": {
"rememberMe": false
},
"registrationDisabled": false,
};
export const kcRegisterContext: KcContext.Register = {
...kcCommonContext,
"url": {
...kcLoginContext.url,
"registrationAction": "http://localhost:8080/auth/realms/myrealm/login-actions/registration?session_code=gwZdUeO7pbYpFTRxiIxRg_QtzMbtFTKrNu6XW_f8asM&execution=12146ce0-b139-4bbd-b25b-0eccfee6577e&client_id=account&tab_id=uS8lYfebLa0"
},
"messagesPerField": {
"printIfExists": (...[, x]) => x
},
"scripts": [],
"isAppInitiatedAction": false,
"pageId": "register.ftl",
"register": {
"formData": {}
},
"passwordRequired": true,
"recaptchaRequired": false,
"authorizedMailDomains": [
"example.com",
"another-example.com",
"*.yet-another-example.com",
"*.example.com",
"hello-world.com"
]
};
export const kcInfoContext: KcContext.Info = {
...kcCommonContext,
"pageId": "info.ftl",
"messageHeader": "<Message header>",
"requiredActions": undefined,
"skipLink": false,
"actionUri": "#",
"client": {
"baseUrl": "#"
}
};
export const kcErrorContext: KcContext.Error = {
...kcCommonContext,
"pageId": "error.ftl",
"client": {
"baseUrl": "#"
}
};
export const kcLoginResetPasswordContext: KcContext.LoginResetPassword = {
...kcCommonContext,
"pageId": "login-reset-password.ftl",
"realm": {
...kcCommonContext.realm,
"loginWithEmailAllowed": false
}
};
export const kcLoginVerifyEmailContext: KcContext.LoginVerifyEmail = {
...kcCommonContext,
"pageId": "login-verify-email.ftl"
};
export const kcTermsContext: KcContext.Terms = {
...kcCommonContext,
"pageId": "terms.ftl"
};
export const kcLoginOtpContext: KcContext.LoginOtp = {
...kcCommonContext,
"pageId": "login-otp.ftl",
"otpLogin": {
"userOtpCredentials": [
{
"id": "id1",
"userLabel": "label1"
},
{
"id": "id2",
"userLabel": "label2"
}
]
}
};

View File

@ -0,0 +1,6 @@
import { join as pathJoin } from "path";
export const subDirOfPublicDirBasename = "keycloak_static";
export const resourcesPath = pathJoin(subDirOfPublicDirBasename, "/resources");
export const resourcesCommonPath = pathJoin(subDirOfPublicDirBasename, "/resources_common");

View File

@ -0,0 +1,118 @@
export declare namespace keycloak_js {
export type KeycloakPromiseCallback<T> = (result: T) => void;
export class KeycloakPromise<TSuccess, TError> extends Promise<TSuccess> {
success(callback: KeycloakPromiseCallback<TSuccess>): KeycloakPromise<TSuccess, TError>;
error(callback: KeycloakPromiseCallback<TError>): KeycloakPromise<TSuccess, TError>;
}
export interface KeycloakAdapter {
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
logout(options?: KeycloakLogoutOptions): KeycloakPromise<void, void>;
register(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
accountManagement(): KeycloakPromise<void, void>;
redirectUri(options: { redirectUri: string; }, encodeHash: boolean): string;
}
export interface KeycloakLogoutOptions {
redirectUri?: string;
}
export interface KeycloakLoginOptions {
scope?: string;
redirectUri?: string;
prompt?: 'none' | 'login';
action?: string;
maxAge?: number;
loginHint?: string;
idpHint?: string;
locale?: string;
cordovaOptions?: { [optionName: string]: string };
}
export type KeycloakInstance = Record<
"createLoginUrl" |
"createLogoutUrl" |
"createRegisterUrl",
(options: KeycloakLoginOptions | undefined) => string
> & {
createAccountUrl(): string;
redirectUri?: string;
}
}
/**
* NOTE: This is just a slightly modified version of the default adapter in keycloak-js
* The goal here is just to be able to inject search param in url before keycloak redirect.
* Our use case for it is to pass over the login screen the states of useGlobalState
* namely isDarkModeEnabled, lgn...
*/
export function createKeycloakAdapter(
params: {
keycloakInstance: keycloak_js.KeycloakInstance;
transformUrlBeforeRedirect(url: string): string;
}
): keycloak_js.KeycloakAdapter {
const { keycloakInstance, transformUrlBeforeRedirect } = params;
const neverResolvingPromise: keycloak_js.KeycloakPromise<void, void> = Object.defineProperties(
new Promise(() => { }),
{
"success": { "value": () => { } },
"error": { "value": () => { } }
}
);
return {
"login": options => {
window.location.href=
transformUrlBeforeRedirect(
keycloakInstance.createLoginUrl(
options
)
);
return neverResolvingPromise;
},
"logout": options => {
window.location.replace(
transformUrlBeforeRedirect(
keycloakInstance.createLogoutUrl(
options
)
)
);
return neverResolvingPromise;
},
"register": options => {
window.location.href =
transformUrlBeforeRedirect(
keycloakInstance.createRegisterUrl(
options
)
);
return neverResolvingPromise;
},
"accountManagement": () => {
var accountUrl = transformUrlBeforeRedirect(keycloakInstance.createAccountUrl());
if (typeof accountUrl !== 'undefined') {
window.location.href = accountUrl;
} else {
throw new Error("Not supported by the OIDC server");
}
return neverResolvingPromise;
},
"redirectUri": options => {
if (options && options.redirectUri) {
return options.redirectUri;
} else if (keycloakInstance.redirectUri) {
return keycloakInstance.redirectUri;
} else {
return window.location.href;
}
}
};
}

2
src/lib/tools/assert.ts Normal file
View File

@ -0,0 +1,2 @@
export { assert } from "evt/tools/typeSafety/assert";

View File

@ -1,12 +0,0 @@
import { sampleReactProjectDirPath } from "./setupSampleReactProject";
import * as st from "scripting-tools";
import { join as pathJoin } from "path";
import { getProjectRoot } from "../bin/tools/getProjectRoot";
st.execSyncTrace(
`node ${pathJoin(getProjectRoot(), "dist", "bin", "download-sample-keycloak-themes")}`,
{ "cwd": sampleReactProjectDirPath }
)

View File

@ -1,7 +1,7 @@
import { join as pathJoin } from "path";
import { generateKeycloakThemeResources } from "../bin/build-keycloak-theme/generateKeycloakThemeResources";
import {
import {
setupSampleReactProject,
sampleReactProjectDirPath
} from "./setupSampleReactProject";
@ -9,8 +9,10 @@ import {
setupSampleReactProject();
generateKeycloakThemeResources({
"themeName": "onyxia-ui",
"themeName": "keycloakify-demo-app",
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme")
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
"urlPathname": "/keycloakify-demo-app/",
"urlOrigin": undefined
});

View File

@ -1,4 +1,5 @@
import {
setupSampleReactProject,
sampleReactProjectDirPath
@ -9,10 +10,15 @@ import { getProjectRoot } from "../bin/tools/getProjectRoot";
setupSampleReactProject();
const binDirPath= pathJoin(getProjectRoot(), "dist", "bin");
st.execSyncTrace(
`node ${pathJoin(getProjectRoot(), "dist", "bin", "build-keycloak-theme")}`,
//`node ${pathJoin(binDirPath, "build-keycloak-theme")} --external-assets`,
`node ${pathJoin(binDirPath, "build-keycloak-theme")}`,
{ "cwd": sampleReactProjectDirPath }
)
);
st.execSyncTrace(
`node ${pathJoin(binDirPath, "install-builtin-keycloak-themes")}`,
{ "cwd": sampleReactProjectDirPath }
);

View File

@ -1,30 +1,47 @@
import { 
replaceImportFromStaticInJsCode,
replaceImportFromStaticInCssCode,
replaceImportsFromStaticInJsCode,
replaceImportsInCssCode,
generateCssCodeToDefineGlobals
} from "../bin/build-keycloak-theme/replaceImportFromStatic";
const { fixedJsCode } = replaceImportFromStaticInJsCode({
"ftlValuesGlobalName": "keycloakFtlValues",
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": `
function f() {
return a.p + "static/js/" + ({}[e] || e) + "." + {
return a.p+"static/js/" + ({}[e] || e) + "." + {
3: "0664cdc0"
}[e] + ".chunk.js"
}
function f2() {
return a.p +"static/js/" + ({}[e] || e) + "." + {
return a.p+"static/js/" + ({}[e] || e) + "." + {
3: "0664cdc0"
}[e] + ".chunk.js"
}
`
`,
"urlOrigin": undefined
});
console.log({ fixedJsCode });
const { fixedJsCode: fixedJsCodeExternal } = replaceImportsFromStaticInJsCode({
"jsCode": `
function f() {
return a.p+"static/js/" + ({}[e] || e) + "." + {
3: "0664cdc0"
}[e] + ".chunk.js"
}
const { fixedCssCode, cssGlobalsToDefine } = replaceImportFromStaticInCssCode({
function f2() {
return a.p+"static/js/" + ({}[e] || e) + "." + {
3: "0664cdc0"
}[e] + ".chunk.js"
}
`,
"urlOrigin": "https://www.example.com"
});
console.log({ fixedJsCode, fixedJsCodeExternal });
const { fixedCssCode, cssGlobalsToDefine } = replaceImportsInCssCode({
"cssCode": `
.my-div {
@ -45,6 +62,6 @@ const { fixedCssCode, cssGlobalsToDefine } = replaceImportFromStaticInCssCode({
console.log({ fixedCssCode, cssGlobalsToDefine });
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine });
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine, "urlPathname": "/" });
console.log({ cssCodeToPrependInHead });

View File

@ -8,7 +8,7 @@ export const sampleReactProjectDirPath = pathJoin(getProjectRoot(), "sample_reac
export function setupSampleReactProject() {
downloadAndUnzip({
"url": "https://github.com/garronej/keycloak-react-theming/releases/download/v0.0.1/sample_build_dir_and_package_json.zip",
"url": "https://github.com/garronej/keycloakify/releases/download/v0.0.1/sample_build_dir_and_package_json.zip",
"destDirPath": sampleReactProjectDirPath
});
}

642
yarn.lock
View File

@ -27,9 +27,9 @@
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
"@babel/highlight@^7.12.13":
version "7.13.8"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.8.tgz#10b2dac78526424dfc1f47650d0e415dfd9dc481"
integrity sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==
version "7.13.10"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1"
integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==
dependencies:
"@babel/helper-validator-identifier" "^7.12.11"
chalk "^2.0.0"
@ -43,9 +43,9 @@
"@babel/helper-plugin-utils" "^7.12.13"
"@babel/runtime@^7.7.2":
version "7.13.8"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.8.tgz#cc886a85c072df1de23670dc1aa59fc116c4017c"
integrity sha512-CwQljpw6qSayc0fRG1soxHAKs1CnQMOChm4mlQP6My0kf9upVGizj/KhlTTgyUnETmHpcUXjaluNAkteRFuafg==
version "7.13.10"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
dependencies:
regenerator-runtime "^0.13.4"
@ -109,9 +109,9 @@
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
"@emotion/serialize@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.0.tgz#1a61f4f037cf39995c97fc80ebe99abc7b191ca9"
integrity sha512-zt1gm4rhdo5Sry8QpCOpopIUIKU+mUSpV9WNmFILUraatm5dttNEaYzUWWSboSMUE6PtN2j1cAsuvcugfdI3mw==
version "1.0.1"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.1.tgz#322cdebfdbb5a88946f17006548191859b9b0855"
integrity sha512-TXlKs5sgUKhFlszp/rg4lIAZd7UUSmJpwaf9/lAEFcUh2vPi32i7x4wk7O8TN8L8v2Ol8k0CxnhRBY0zQalTxA==
dependencies:
"@emotion/hash" "^0.8.0"
"@emotion/memoize" "^0.7.4"
@ -139,117 +139,17 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@octokit/auth-token@^2.4.4":
version "2.4.5"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
"@types/mdast@^3.0.0", "@types/mdast@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb"
integrity sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==
dependencies:
"@octokit/types" "^6.0.3"
"@octokit/core@^3.2.3":
version "3.2.5"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.2.5.tgz#57becbd5fd789b0592b915840855f3a5f233d554"
integrity sha512-+DCtPykGnvXKWWQI0E1XD+CCeWSBhB6kwItXqfFmNBlIlhczuDPbg+P6BtLnVBaRJDAjv+1mrUJuRsFSjktopg==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.4.12"
"@octokit/types" "^6.0.3"
before-after-hook "^2.1.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^6.0.1":
version "6.0.11"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1"
integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==
dependencies:
"@octokit/types" "^6.0.3"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^4.5.8":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.0.tgz#f9abca55f82183964a33439d5264674c701c3327"
integrity sha512-CJ6n7izLFXLvPZaWzCQDjU/RP+vHiZmWdOunaCS87v+2jxMsW9FB5ktfIxybRBxZjxuJGRnxk7xJecWTVxFUYQ==
dependencies:
"@octokit/request" "^5.3.0"
"@octokit/types" "^6.0.3"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.2.0.tgz#54e6ca0bc2cd54cd93f0a64658e893c32a5e69ec"
integrity sha512-MInMij2VK5o96Ei6qaHjxBglSZWOXQs9dTZfnGX2Xnr2mhA+yk9L/QCH4RcJGISJJCBclLHuY3ytq+iRgDfX7w==
"@octokit/plugin-paginate-rest@^2.6.2":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.11.0.tgz#3568c43896a3355f4a0bbb3a64f443b2abdc760d"
integrity sha512-7L9xQank2G3r1dGqrVPo1z62V5utbykOUzlmNHPz87Pww/JpZQ9KyG5CHtUzgmB4n5iDRKYNK/86A8D98HP0yA==
dependencies:
"@octokit/types" "^6.11.0"
"@octokit/plugin-request-log@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d"
integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==
"@octokit/plugin-rest-endpoint-methods@4.13.0":
version "4.13.0"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.0.tgz#59a90f59a564d416214ab191c3ffcd641f175e6a"
integrity sha512-Ofusy7BwHkU7z4TNsVdf7wm5W3KR625KqlQj4AiWPnBvclmZU0Y2bVK8b8Mz8nW7sEX9TJcCdX6KeaincE/cLw==
dependencies:
"@octokit/types" "^6.11.0"
deprecation "^2.3.1"
"@octokit/request-error@^2.0.0":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143"
integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==
dependencies:
"@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.3.0", "@octokit/request@^5.4.12":
version "5.4.14"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.14.tgz#ec5f96f78333bb2af390afa5ff66f114b063bc96"
integrity sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.0.0"
"@octokit/types" "^6.7.1"
deprecation "^2.0.0"
is-plain-object "^5.0.0"
node-fetch "^2.6.1"
once "^1.4.0"
universal-user-agent "^6.0.0"
"@octokit/rest@^18.0.0":
version "18.3.0"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.3.0.tgz#c326475a2039ffeaec9a1498ebee14a561aae4e5"
integrity sha512-R45oBVhnq3HAOGVtC6lHY7LX7TGWqbbcD4KvBHoT4QIjgJzfqKag3m/DUJwLnp8xrokz1spZmspTIXiDeQqJSA==
dependencies:
"@octokit/core" "^3.2.3"
"@octokit/plugin-paginate-rest" "^2.6.2"
"@octokit/plugin-request-log" "^1.0.2"
"@octokit/plugin-rest-endpoint-methods" "4.13.0"
"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.7.1":
version "6.11.0"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.11.0.tgz#830a608882cde659be19a6e86568abaa619e2ee7"
integrity sha512-RMLAmpPZf/a33EsclBazKg02NCCj4rC69V9sUgf0SuWTjmnBD2QC1nIVtJo7RJrGnwG1+aoFBb2yTrWm/8AS7w==
dependencies:
"@octokit/openapi-types" "^5.2.0"
"@types/comment-json@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/comment-json/-/comment-json-1.1.1.tgz#b4ae889912a93e64619f97989aecaff8ce889dca"
integrity sha512-U70oEqvnkeSSp8BIJwJclERtT13rd9ejK7XkIzMCQQePZe3VW1b7iQggXyW4ZvfGtGeXD0pZw24q5iWNe++HqQ==
"@types/unist" "*"
"@types/node@^10.0.0":
version "10.17.54"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.54.tgz#a737488631aca3ec7bd9f6229d77f1079e444793"
integrity sha512-c8Lm7+hXdSPmWH4B9z/P/xIXhFK3mCQin4yCYMd2p1qpMG5AfgyJuYZ+3q2dT7qLiMMMGMd5dnkFpdqJARlvtQ==
version "10.17.55"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.55.tgz#a147f282edec679b894d4694edb5abeb595fecbd"
integrity sha512-koZJ89uLZufDvToeWO5BrC4CR4OUfHnUz2qoPs/daQH6qq3IN62QFxCTZ+bKaCE0xaoCAJYE4AXre8AbghCrhg==
"@types/parse-json@^4.0.0":
version "4.0.0"
@ -262,13 +162,29 @@
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react@^17.0.0":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8"
integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==
version "17.0.3"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.3.tgz#ba6e215368501ac3826951eef2904574c262cc79"
integrity sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.1"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
ansi-regex@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
@ -297,16 +213,16 @@ babel-plugin-macros@^2.6.1:
cosmiconfig "^6.0.0"
resolve "^1.12.0"
bail@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776"
integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
before-after-hook@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.1.tgz#99ae36992b5cfab4a83f6bee74ab27835f28f405"
integrity sha512-5ekuQOvO04MDj7kYZJaMab2S8SPjGJbotVNyv7QYFCOAwrGZs/YnoDNlh1U+m5hl7H2D/+n0taaAV/tfyd3KMA==
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@ -334,6 +250,21 @@ chalk@^2.0.0:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
character-entities-legacy@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1"
integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==
character-entities@^1.0.0:
version "1.2.4"
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b"
integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==
character-reference-invalid@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
cheerio-select-tmp@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz#55bbef02a4771710195ad736d5e346763ca4e646"
@ -391,21 +322,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
commander@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
comment-json@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-3.0.3.tgz#0cadacd6278602b57b8c51b1814dc5d311d228c4"
integrity sha512-P7XwYkC3qjIK45EAa9c5Y3lR7SMXhJqwFdWg3niAIAcbk3zlpKDdajV8Hyz/Y3sGNn3l+YNMl8A2N/OubSArHg==
dependencies:
core-util-is "^1.0.2"
esprima "^4.0.1"
has-own-prop "^2.0.0"
repeat-string "^1.6.1"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -431,7 +347,7 @@ copyfiles@^2.4.1:
untildify "^4.0.0"
yargs "^16.1.0"
core-util-is@^1.0.2, core-util-is@~1.0.0:
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
@ -476,28 +392,12 @@ d@1, d@^1.0.1:
es5-ext "^0.10.50"
type "^1.0.1"
denoify@^0.6.5:
version "0.6.5"
resolved "https://registry.yarnpkg.com/denoify/-/denoify-0.6.5.tgz#06512be38026ec0f2033db9566d07428e63d56bf"
integrity sha512-AhKBlvO91QdP5T/fRcxiMj3b6cDe5ucr+7YVlePXCuV/kImbiR0V1qjGTCfmVuC3wvRn5Xf6r34qJJRbo86AqA==
debug@^4.0.0:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
"@octokit/rest" "^18.0.0"
"@types/comment-json" "^1.1.1"
commander "^4.1.1"
comment-json "^3.0.2"
evt "^1.9.2"
get-github-default-branch-name "^0.0.4"
gitignore-parser "0.0.2"
glob "^7.1.6"
node-fetch "^2.6.0"
path-depth "^1.0.0"
scripting-tools "^0.19.13"
url-join "^4.0.1"
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
ms "2.1.2"
dom-serializer@^1.0.1, dom-serializer@~1.2.0:
version "1.2.0"
@ -513,6 +413,18 @@ domelementtype@^2.0.1, domelementtype@^2.1.0:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e"
integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==
domelementtype@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
domhandler@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a"
integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==
dependencies:
domelementtype "^2.0.1"
domhandler@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.0.0.tgz#01ea7821de996d85f69029e81fa873c21833098e"
@ -520,10 +432,26 @@ domhandler@^4.0.0:
dependencies:
domelementtype "^2.1.0"
domhandler@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.1.0.tgz#c1d8d494d5ec6db22de99e46a149c2a4d23ddd43"
integrity sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==
dependencies:
domelementtype "^2.2.0"
domutils@^2.4.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.5.2.tgz#37ef8ba087dff1a17175e7092e8a042e4b050e6c"
integrity sha512-MHTthCb1zj8f1GVfRpeZUbohQf/HdBos0oX5gZcQFepOZPLLRyj6Wn7XS7EMnY7CVpwv8863u2vyE83Hfu28HQ==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
domhandler "^4.1.0"
domutils@^2.4.3, domutils@^2.4.4:
version "2.4.4"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.4.4.tgz#282739c4b150d022d34699797369aad8d19bbbd3"
integrity sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==
version "2.5.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.5.0.tgz#42f49cffdabb92ad243278b331fd761c1c2d3039"
integrity sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.0.1"
@ -602,11 +530,6 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
esprima@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
event-emitter@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
@ -615,18 +538,10 @@ event-emitter@^0.3.5:
d "1"
es5-ext "~0.10.14"
evt@2.0.0-beta.12:
version "2.0.0-beta.12"
resolved "https://registry.yarnpkg.com/evt/-/evt-2.0.0-beta.12.tgz#d24724ea4c70e78af3eb73dbbf3ece81d295a1e7"
integrity sha512-KoDNXD73aKIGhylvFVYyEjoTTHKWofi0ozaRrvW4rjXZ1XbSUEat+iGSsy/S387v3ZkKB9UI499hT7WtNGzSrw==
dependencies:
minimal-polyfills "^2.1.5"
run-exclusive "^2.2.14"
evt@^1.9.12, evt@^1.9.2:
version "1.9.12"
resolved "https://registry.yarnpkg.com/evt/-/evt-1.9.12.tgz#8d06177259cbcb09ef936e18945bf7ddd087170c"
integrity sha512-u8wC4Xif2pcDJ9cEm0wzWCIQb+Y214m1eUgsgm2hVIuXuvC6LToryA0Ecl1O8Slii2E9l6USLsyxXWntjlnIbw==
evt@2.0.0-beta.15:
version "2.0.0-beta.15"
resolved "https://registry.yarnpkg.com/evt/-/evt-2.0.0-beta.15.tgz#a34ef224c827152c06f29157a9af5a41644e1a36"
integrity sha512-AZIuA8ujBsDX/rPC9mJ2sGvrBJAvV2OGj/yzACbuT4pRLKii5PMjYPitNk4xJMKuXSDwvwCsQzuGPDCcbRc60A==
dependencies:
minimal-polyfills "^2.1.5"
run-exclusive "^2.2.14"
@ -638,6 +553,11 @@ ext@^1.1.2:
dependencies:
type "^2.0.0"
extend@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
@ -658,20 +578,7 @@ get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-github-default-branch-name@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/get-github-default-branch-name/-/get-github-default-branch-name-0.0.4.tgz#9c0c6606ba606edb136d2fd26e4d515b69f2de90"
integrity sha512-ltOGC9Jk0k8boe48Gk7SkJErwxt7MhwXtbNrBUyNCZcwcXSmGRdkKb2u0YO250PGvPsUtdqRjg7lVuIk1VtpCg==
dependencies:
"@octokit/rest" "^18.0.0"
scripting-tools "^0.19.12"
gitignore-parser@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/gitignore-parser/-/gitignore-parser-0.0.2.tgz#f61259b985dd91414b9a7168faef9171c2eec5df"
integrity sha1-9hJZuYXdkUFLmnFo+u+RccLuxd8=
glob@^7.0.5, glob@^7.1.3, glob@^7.1.6:
glob@^7.0.5, glob@^7.1.3:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@ -688,11 +595,6 @@ has-flag@^3.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-own-prop@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af"
integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@ -700,10 +602,30 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
html-to-react@^1.3.4:
version "1.4.5"
resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.5.tgz#59091c11021d1ef315ef738460abb6a4a41fe1ce"
integrity sha512-KONZUDFPg5OodWaQu2ymfkDmU0JA7zB1iPfvyHehTmMUZnk0DS7/TyCMTzsLH6b4BvxX15g88qZCXFhJWktsmA==
dependencies:
domhandler "^3.3.0"
htmlparser2 "^5.0"
lodash.camelcase "^4.3.0"
ramda "^0.27.1"
htmlparser2@^5.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-5.0.1.tgz#7daa6fc3e35d6107ac95a4fc08781f091664f6e7"
integrity sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==
dependencies:
domelementtype "^2.0.1"
domhandler "^3.3.0"
domutils "^2.4.2"
entities "^2.0.0"
htmlparser2@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.0.0.tgz#c2da005030390908ca4c91e5629e418e0665ac01"
integrity sha512-numTQtDZMoh78zJpaNdJ9MXb2cv5G3jwUoe3dMQODubZvLoGvTE/Ofp6sHvH8OGKcN/8A47pGLi/k58xHP/Tfw==
version "6.0.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.0.1.tgz#422521231ef6d42e56bd411da8ba40aa36e91446"
integrity sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
@ -731,11 +653,34 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
is-alphabetical@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d"
integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==
is-alphanumerical@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf"
integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==
dependencies:
is-alphabetical "^1.0.0"
is-decimal "^1.0.0"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
is-buffer@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
is-core-module@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
@ -743,15 +688,25 @@ is-core-module@^2.2.0:
dependencies:
has "^1.0.3"
is-decimal@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5"
integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-hexadecimal@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
is-plain-obj@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
is-promise@^2.2.2:
version "2.2.2"
@ -783,12 +738,17 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash@^4.17.19:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.1.0:
loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -802,6 +762,36 @@ lru-queue@^0.1.0:
dependencies:
es5-ext "~0.10.2"
markdown@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/markdown/-/markdown-0.5.0.tgz#28205b565a8ae7592de207463d6637dc182722b2"
integrity sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=
dependencies:
nopt "~2.1.1"
mdast-add-list-metadata@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz#95e73640ce2fc1fa2dcb7ec443d09e2bfe7db4cf"
integrity sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==
dependencies:
unist-util-visit-parents "1.1.2"
mdast-util-from-markdown@^0.8.0:
version "0.8.5"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c"
integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-string "^2.0.0"
micromark "~2.11.0"
parse-entities "^2.0.0"
unist-util-stringify-position "^2.0.0"
mdast-util-to-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b"
integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==
memoizee@^0.4.15:
version "0.4.15"
resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72"
@ -816,6 +806,14 @@ memoizee@^0.4.15:
next-tick "^1.1.0"
timers-ext "^0.1.7"
micromark@~2.11.0:
version "2.11.4"
resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a"
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
dependencies:
debug "^4.0.0"
parse-entities "^2.0.0"
minimal-polyfills@^2.1.5, minimal-polyfills@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/minimal-polyfills/-/minimal-polyfills-2.1.6.tgz#eab50832add31afd40a22b38fb76d1fdcd2a51e4"
@ -833,6 +831,11 @@ mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
next-tick@1, next-tick@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
@ -843,11 +846,6 @@ next-tick@~1.0.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
node-fetch@^2.6.0, node-fetch@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
noms@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
@ -856,6 +854,13 @@ noms@0.0.0:
inherits "^2.0.1"
readable-stream "~1.0.31"
nopt@~2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-2.1.2.tgz#6cccd977b80132a07731d6e8ce58c2c8303cf9af"
integrity sha1-bMzZd7gBMqB3MdbozljCyDA8+a8=
dependencies:
abbrev "1"
nth-check@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
@ -868,7 +873,7 @@ object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
once@^1.3.0, once@^1.4.0:
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@ -882,6 +887,18 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==
dependencies:
character-entities "^1.0.0"
character-entities-legacy "^1.0.0"
character-reference-invalid "^1.0.0"
is-alphanumerical "^1.0.0"
is-decimal "^1.0.0"
is-hexadecimal "^1.0.0"
parse-json@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
@ -904,11 +921,6 @@ parse5@^6.0.0, parse5@^6.0.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
path-depth@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/path-depth/-/path-depth-1.0.0.tgz#88cf881097e171b8b54d450d2167ea76063d3086"
integrity sha512-dEiwdXAQyLvOi6ktLqhFhjVelJiVsdp2xBX3BaUtYCCkMRZTwUiq7cha+A0myvAVXRHbXfjhfTf4mNoAWzm2iA==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@ -924,12 +936,20 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
powerhooks@^0.0.14:
version "0.0.14"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.0.14.tgz#1456620de2d2b899f54509a8ef909c4c15694c81"
integrity sha512-fse74qwumuETne++wc3asYlhuaQYvKHUUzsAbNQfBb5OK3J12KbBYM3kh+ZPOf5C9/OAJg/qAAXsz2G/5ROS4w==
path@^0.12.7:
version "0.12.7"
resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=
dependencies:
evt "2.0.0-beta.12"
process "^0.11.1"
util "^0.10.3"
powerhooks@^0.0.36:
version "0.0.36"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.0.36.tgz#d973d339ad8ca7ce52ea9d288ebe8e138df7d769"
integrity sha512-0fEGKLfJmuFeEYDGsAlTuvGKKdqOH059xezosmYRoGurfC1bbUlaNJD+TuzOT5cTGURi88DCLcDnhk/2eLyCyA==
dependencies:
evt "2.0.0-beta.15"
memoizee "^0.4.15"
resize-observer-polyfill "^1.5.1"
@ -938,6 +958,20 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process@^0.11.1:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
properties-parser@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/properties-parser/-/properties-parser-0.3.1.tgz#1316e9539ffbfd93845e369b211022abd478771a"
@ -945,6 +979,32 @@ properties-parser@^0.3.1:
dependencies:
string.prototype.codepointat "^0.2.0"
ramda@^0.27.1:
version "0.27.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9"
integrity sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==
react-is@^16.8.1, react-is@^16.8.6:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-markdown@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-5.0.3.tgz#41040ea7a9324b564b328fb81dd6c04f2a5373ac"
integrity sha512-jDWOc1AvWn0WahpjW6NK64mtx6cwjM4iSsLHJPNBqoAgGOVoIdJMqaKX4++plhOtdd4JksdqzlDibgPx6B/M2w==
dependencies:
"@types/mdast" "^3.0.3"
"@types/unist" "^2.0.3"
html-to-react "^1.3.4"
mdast-add-list-metadata "1.0.1"
prop-types "^15.7.2"
react-is "^16.8.6"
remark-parse "^9.0.0"
unified "^9.0.0"
unist-util-visit "^2.0.0"
xtend "^4.0.1"
react@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127"
@ -981,10 +1041,12 @@ regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
remark-parse@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640"
integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==
dependencies:
mdast-util-from-markdown "^0.8.0"
require-directory@^2.1.1:
version "2.1.1"
@ -1028,7 +1090,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
scripting-tools@^0.19.12, scripting-tools@^0.19.13:
scripting-tools@^0.19.13:
version "0.19.13"
resolved "https://registry.yarnpkg.com/scripting-tools/-/scripting-tools-0.19.13.tgz#836df7d9c2ec99aea91984d1d5b2bd110670afec"
integrity sha512-d09H8vzSVa8p4XUTJqHZDbjKDyl5TG3SyPfNPUUkfyOwjwykStmfK8AXyWq7VRWjcgzTpkTiJ9uMk1NytMQY7w==
@ -1104,10 +1166,15 @@ to-fast-properties@^2.0.0:
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
tss-react@^0.0.9:
version "0.0.9"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-0.0.9.tgz#4f07be32ad8a9c7db2881236b80fd4715384fe92"
integrity sha512-1Vo1UQrj18RaQIla/pes717iBzuYwVpQq/BdK/jREpm6kVS4HpoYXQlM0A0wp2ToG3kvFdop5STqowW3sviCfw==
trough@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
tss-react@^0.0.12:
version "0.0.12"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-0.0.12.tgz#6463617ae5e7f670742e48e497d8825d59e2a2e9"
integrity sha512-oHekukqdaE71uhHx4XEdHy6aMnDYhoHLWB94iy2Fy9X8btH2lJH1joPj0zS1q7+1Xy2TydkLEZsTq3ElVd7ZqA==
dependencies:
"@emotion/css" "^11.1.3"
@ -1117,35 +1184,96 @@ type@^1.0.1:
integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
type@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/type/-/type-2.3.0.tgz#ada7c045f07ead08abf9e2edd29be1a0c0661132"
integrity sha512-rgPIqOdfK/4J9FhiVrZ3cveAjRRo5rsQBAIhnylX874y1DX/kEKSVdLsnuHB6l1KTjHyU01VjiMBHgU2adejyg==
version "2.5.0"
resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d"
integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==
typescript@^4.1.5:
version "4.2.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c"
integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==
typescript@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
unified@^9.0.0:
version "9.2.1"
resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.1.tgz#ae18d5674c114021bfdbdf73865ca60f410215a3"
integrity sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==
dependencies:
bail "^1.0.0"
extend "^3.0.0"
is-buffer "^2.0.0"
is-plain-obj "^2.0.0"
trough "^1.0.0"
vfile "^4.0.0"
unist-util-is@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797"
integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==
unist-util-stringify-position@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da"
integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==
dependencies:
"@types/unist" "^2.0.2"
unist-util-visit-parents@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz#f6e3afee8bdbf961c0e6f028ea3c0480028c3d06"
integrity sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q==
unist-util-visit-parents@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6"
integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==
dependencies:
"@types/unist" "^2.0.0"
unist-util-is "^4.0.0"
unist-util-visit@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c"
integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==
dependencies:
"@types/unist" "^2.0.0"
unist-util-is "^4.0.0"
unist-util-visit-parents "^3.0.0"
untildify@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
url-join@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7"
integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
util@^0.10.3:
version "0.10.4"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
dependencies:
inherits "2.0.3"
vfile-message@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==
dependencies:
"@types/unist" "^2.0.0"
unist-util-stringify-position "^2.0.0"
vfile@^4.0.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624"
integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==
dependencies:
"@types/unist" "^2.0.0"
is-buffer "^2.0.0"
unist-util-stringify-position "^2.0.0"
vfile-message "^2.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
@ -1160,7 +1288,7 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
xtend@~4.0.1:
xtend@^4.0.1, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
@ -1171,14 +1299,14 @@ y18n@^5.0.5:
integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==
yaml@^1.7.2:
version "1.10.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@^20.2.2:
version "20.2.6"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.6.tgz#69f920addf61aafc0b8b89002f5d66e28f2d8b20"
integrity sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA==
version "20.2.7"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
yargs@^16.1.0:
version "16.2.0"