Compare commits
299 Commits
Author | SHA1 | Date | |
---|---|---|---|
28036f1da5 | |||
0dacf2fe30 | |||
32f5ef5e5c | |||
98d91bbde7 | |||
7a92a75d83 | |||
f5556a02fc | |||
1050f4d928 | |||
9276b08f4b | |||
a501af669c | |||
85343fcefe | |||
b11dfde6e6 | |||
38d2108f02 | |||
2b67544517 | |||
0d443ca88e | |||
71f7a5819d | |||
5f4abee615 | |||
f5ee949006 | |||
7e85085558 | |||
55a0b27f16 | |||
eb0e814f94 | |||
b7fe20c5a5 | |||
2b23d03ca5 | |||
7075be20c8 | |||
3ce8b06246 | |||
ee5c29f30f | |||
242dad3ea0 | |||
d8701925df | |||
e2d669ce31 | |||
af93664c71 | |||
daa3efa534 | |||
2c7c8397f0 | |||
821ba2cbe2 | |||
a17ddb02fa | |||
b89557e8d8 | |||
cad1f8b957 | |||
f82cc788bf | |||
06f9cd3e68 | |||
5113a838e7 | |||
645a84c82a | |||
925fc43d0f | |||
8e33d24c63 | |||
984ef63661 | |||
a8daf175ea | |||
055263a3da | |||
9990b0ab05 | |||
423397ce3e | |||
954567712c | |||
9f52eb8123 | |||
744b198fb4 | |||
15eab797c3 | |||
8ff86b1e29 | |||
e1b8760ee3 | |||
bd0d890b2c | |||
2a2118d769 | |||
9839b64650 | |||
2bf55e12f9 | |||
2249fa9232 | |||
f673a65304 | |||
0163459ad6 | |||
b21123cc9d | |||
7800d125b2 | |||
89ea648f18 | |||
ab7ac3c2d0 | |||
b16319d962 | |||
f8012d5dfb | |||
45a2015597 | |||
524ab000be | |||
d73cfb8765 | |||
8164f5373f | |||
824b0c275e | |||
f8d83d7a37 | |||
b291526b13 | |||
e1c310d383 | |||
242777a8eb | |||
10a6b70fe9 | |||
c829f5969c | |||
ba6a5047b1 | |||
852f48c05f | |||
c342f04a92 | |||
42eb8147c6 | |||
ebcdbd782f | |||
d2059e08d1 | |||
4f075882d5 | |||
044ec1a2da | |||
a49a32703d | |||
46ec832767 | |||
fc858b3db6 | |||
3cd8843157 | |||
c9358ea8dd | |||
354a4db0f6 | |||
90d435d96b | |||
2d804f0f0f | |||
1c9acedac0 | |||
6e914e4ea3 | |||
f0c4786267 | |||
0b16159312 | |||
ea8a91e069 | |||
59db202fe4 | |||
09927afd43 | |||
13c6122b9b | |||
1bb19f65a2 | |||
918a80cfb6 | |||
ed7d5eabcb | |||
2795109162 | |||
966f277628 | |||
36d60411f9 | |||
60fe33f3fd | |||
1df685df92 | |||
7894d95ace | |||
a8b4493aa1 | |||
715a7399cf | |||
a1e59bae23 | |||
b0819314a1 | |||
0099442543 | |||
66a0b07228 | |||
85f9544754 | |||
2f16a09ab8 | |||
183ae98c30 | |||
ba15e63879 | |||
654277feda | |||
81279a5cc5 | |||
59f0a843b0 | |||
c094f70171 | |||
0858fe6319 | |||
5012ec0ccc | |||
990a24fab2 | |||
036b6bf82a | |||
8272a02b52 | |||
e346b1d9d2 | |||
2309bd21c6 | |||
7d6476c1b5 | |||
e892a0e7e6 | |||
ca5b41e730 | |||
9b18234112 | |||
5274368f47 | |||
1415c24028 | |||
4a084f5859 | |||
a30c9eb0cd | |||
85d3b40b8e | |||
335afec230 | |||
69fa49848a | |||
7a09051127 | |||
07ee0ecb8b | |||
6f133428f8 | |||
4f733736db | |||
d96ff13a67 | |||
2c1351ce47 | |||
96cd56ec77 | |||
e5b2096d65 | |||
3aa140335f | |||
4cafaa2492 | |||
9c633a7521 | |||
e27845ba91 | |||
2a8708a45b | |||
6874fa4c24 | |||
ba531a4927 | |||
20175b57cf | |||
ad275e4c34 | |||
060b9fe0de | |||
17b24d14ed | |||
2d278b0680 | |||
fb5975e4f1 | |||
24fccaf513 | |||
293953aa1b | |||
1049e312f9 | |||
a2db250600 | |||
cf7fe8c337 | |||
f5350097bf | |||
1cb5dd461b | |||
845599a5e8 | |||
0cc02c292f | |||
1919702326 | |||
0c0052e1cd | |||
78622770ec | |||
7b86727394 | |||
0965f8648e | |||
98974b4367 | |||
597bcadd9e | |||
4d9aabcb91 | |||
1606c2884d | |||
12f69b593f | |||
1ca45f90d0 | |||
a91a5616f9 | |||
c525e09368 | |||
f5bba4a6a0 | |||
77a37fb573 | |||
6b24c5878c | |||
f4414e1249 | |||
b72971f4ce | |||
b9af4e6804 | |||
2fd1d42d1e | |||
3cfc7d7fa9 | |||
b5d9055fcf | |||
63d644d95f | |||
e16192b416 | |||
505e018448 | |||
5ced0e2809 | |||
0e1d919f7e | |||
a009db998e | |||
d6c6bd933b | |||
859cc03f35 | |||
1a3b8ae3b8 | |||
863a08abf3 | |||
fd9c6afa5e | |||
8f3797407b | |||
7eedb23285 | |||
e4a2c95dd8 | |||
9429228b71 | |||
aafbc60f12 | |||
7170611791 | |||
59e57f3dd5 | |||
fd0d25b081 | |||
fa529c911a | |||
dc997b7ef4 | |||
0168d32f96 | |||
d6fc0c779c | |||
08be36edfa | |||
990d287953 | |||
a629d4ab45 | |||
78b48af886 | |||
72d267853c | |||
66a218c2ec | |||
d4f3ec2245 | |||
7bdc19bf4b | |||
103ef788fb | |||
b6f6d1f3cc | |||
ef3d2e4e04 | |||
8ec8b91ead | |||
819a1d473d | |||
c930337255 | |||
57bb4a9d96 | |||
1776341242 | |||
983eec6941 | |||
86d390ee1a | |||
91703409d9 | |||
3322d0e4a5 | |||
d09038fde2 | |||
71966deaac | |||
12e83c9468 | |||
fe27357dbb | |||
b93003e76d | |||
d6c0e9f783 | |||
18a1baae59 | |||
2330788995 | |||
40c146022a | |||
9844e7554f | |||
b064b8cbe6 | |||
997941fbf7 | |||
8d5e080bd6 | |||
1c1ca25287 | |||
5195b3bc1e | |||
3ff56cfea7 | |||
adc6d69201 | |||
438ca4595f | |||
740d9b7af5 | |||
919a6947bc | |||
85fdaa2f22 | |||
6ade3d6375 | |||
73e9ebbe40 | |||
ad78221025 | |||
714fec0bf3 | |||
de312c60b1 | |||
1d07fd7675 | |||
307650aaea | |||
6eccd313b6 | |||
b8751d67db | |||
25d9d3dc26 | |||
68e6c9faaf | |||
f3fb360ce0 | |||
d3631dd10c | |||
891c91aa20 | |||
880018e926 | |||
06ab2ab82e | |||
aafcfb62f2 | |||
a69bee8726 | |||
240208793d | |||
e7a320f8f8 | |||
f76438dd82 | |||
d6dbb42dea | |||
2e076aa058 | |||
b59447b840 | |||
702352bea2 | |||
98f647fadf | |||
85d3a011d8 | |||
26b0b55a7d | |||
50d0e74c03 | |||
5a7fb7c303 | |||
e9f5a79d69 | |||
1378dbebee | |||
7daa818996 | |||
c8e219361b | |||
b74323a48e | |||
0cfe240590 | |||
533105d63a | |||
62e4af2c78 | |||
934c07f365 | |||
624409434a | |||
546c74aa28 | |||
2ee12abc43 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1,3 +1,3 @@
|
|||||||
src/lib/i18n/generated_messages/* linguist-documentation
|
src/lib/i18n/generated_messages/* linguist-documentation
|
||||||
|
src/bin/install-builtin-keycloak-themes.ts -linguist-detectable
|
||||||
src/bin/build-keycloak-theme/index.ts -linguist-detectable
|
src/bin/build-keycloak-theme/index.ts -linguist-detectable
|
||||||
src/bin/download-sample-keycloak-themes.ts -linguist-detectable
|
|
159
.github/workflows/ci.yaml
vendored
159
.github/workflows/ci.yaml
vendored
@ -2,87 +2,128 @@ name: ci
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- develop
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- develop
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
test_node:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: macos-10.15
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node: [ '14', '13', '12' ]
|
node: [ '15', '14', '13' ]
|
||||||
name: Test with Node v${{ matrix.node }}
|
name: Test with Node v${{ matrix.node }}
|
||||||
steps:
|
steps:
|
||||||
- name: Tell if project is using npm or yarn
|
- name: Tell if project is using npm or yarn
|
||||||
id: _1
|
id: step1
|
||||||
uses: garronej/github_actions_toolkit@v1.11
|
uses: garronej/github_actions_toolkit@v2.2
|
||||||
with:
|
with:
|
||||||
action_name: tell_if_project_uses_npm_or_yarn
|
action_name: tell_if_project_uses_npm_or_yarn
|
||||||
owner: ${{github.repository_owner}}
|
- uses: actions/checkout@v2.3.4
|
||||||
repo: ${{github.event.repository.name}}
|
- uses: actions/setup-node@v2.1.3
|
||||||
branch: ${{github.ref}}
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
- if: steps._1.outputs.npm_or_yarn == 'yarn'
|
- uses: bahmutov/npm-install@v1
|
||||||
|
- if: steps.step1.outputs.npm_or_yarn == 'yarn'
|
||||||
run: |
|
run: |
|
||||||
yarn install --frozen-lockfile
|
yarn build
|
||||||
yarn run build
|
yarn test
|
||||||
yarn run test
|
- if: steps.step1.outputs.npm_or_yarn == 'npm'
|
||||||
- if: steps._1.outputs.npm_or_yarn == 'npm'
|
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
|
||||||
npm run build
|
npm run build
|
||||||
npm run test
|
npm test
|
||||||
trigger_publish:
|
check_if_version_upgraded:
|
||||||
name: Trigger publish.yaml workflow if package.json version updated ( and secrets.PAT is set ).
|
name: Check if version upgrade
|
||||||
|
if: github.event_name == 'push'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
needs: test
|
||||||
PAT: ${{secrets.PAT}}
|
outputs:
|
||||||
if: github.event_name == 'push' && github.event.head_commit.author.name != 'ts_ci'
|
from_version: ${{ steps.step1.outputs.from_version }}
|
||||||
needs: test_node
|
to_version: ${{ steps.step1.outputs.to_version }}
|
||||||
|
is_upgraded_version: ${{steps.step1.outputs.is_upgraded_version }}
|
||||||
steps:
|
steps:
|
||||||
|
- uses: garronej/github_actions_toolkit@v2.2
|
||||||
- name: Get version on latest
|
id: step1
|
||||||
id: v_latest
|
|
||||||
uses: garronej/github_actions_toolkit@v1.11
|
|
||||||
with:
|
with:
|
||||||
action_name: get_package_json_version
|
action_name: is_package_json_version_upgraded
|
||||||
owner: ${{github.repository_owner}}
|
|
||||||
repo: ${{github.event.repository.name}}
|
|
||||||
branch: latest
|
|
||||||
compare_to_version: '0.0.0'
|
|
||||||
|
|
||||||
- name: Get version on develop
|
update_changelog:
|
||||||
id: v_develop
|
runs-on: ubuntu-latest
|
||||||
uses: garronej/github_actions_toolkit@v1.11
|
needs: check_if_version_upgraded
|
||||||
|
if: needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true'
|
||||||
|
steps:
|
||||||
|
- uses: garronej/github_actions_toolkit@v2.4
|
||||||
with:
|
with:
|
||||||
action_name: get_package_json_version
|
action_name: update_changelog
|
||||||
owner: ${{github.repository_owner}}
|
branch: ${{ github.ref }}
|
||||||
repo: ${{github.event.repository.name}}
|
|
||||||
branch: ${{ github.sha }}
|
|
||||||
compare_to_version: ${{steps.v_latest.outputs.version || '0.0.0'}}
|
|
||||||
|
|
||||||
- name: 'Trigger the ''publish'' workflow'
|
create_github_release:
|
||||||
if: ${{ !!env.PAT && steps.v_develop.outputs.compare_result == '1' }}
|
runs-on: ubuntu-latest
|
||||||
uses: garronej/github_actions_toolkit@v1.11
|
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:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
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:
|
with:
|
||||||
action_name: dispatch_event
|
name: Release v${{ needs.check_if_version_upgraded.outputs.to_version }}
|
||||||
owner: ${{github.repository_owner}}
|
tag_name: v${{ needs.check_if_version_upgraded.outputs.to_version }}
|
||||||
repo: ${{github.event.repository.name}}
|
target_commitish: ${{ github.ref }}
|
||||||
event_type: publish
|
body: ${{ steps.step1.outputs.body }}
|
||||||
client_payload_json: |
|
draft: false
|
||||||
${{
|
prerelease: false
|
||||||
format(
|
env:
|
||||||
'{{"from_version":"{0}","to_version":"{1}","repo":"{2}"}}',
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
steps.v_latest.outputs.version,
|
|
||||||
steps.v_develop.outputs.version,
|
publish_on_npm:
|
||||||
github.event.repository.name
|
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'
|
||||||
|
registry-url: https://registry.npmjs.org/
|
||||||
|
- uses: bahmutov/npm-install@v1
|
||||||
|
- run: |
|
||||||
|
PACKAGE_MANAGER=npm
|
||||||
|
if [ -f "./yarn.lock" ]; then
|
||||||
|
PACKAGE_MANAGER=yarn
|
||||||
|
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 [ "$NODE_AUTH_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
|
||||||
|
npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||||
|
VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}
|
116
.github/workflows/publish.yaml
vendored
116
.github/workflows/publish.yaml
vendored
@ -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 }}
|
|
308
CHANGELOG.md
308
CHANGELOG.md
@ -1,3 +1,311 @@
|
|||||||
|
### **1.1.6** (2021-06-21)
|
||||||
|
|
||||||
|
- Fix: Alert messages sometimes includes HTML that is not rendered
|
||||||
|
- Update dist
|
||||||
|
|
||||||
|
### **1.1.5** (2021-06-15)
|
||||||
|
|
||||||
|
- #11: Provide socials in the register
|
||||||
|
|
||||||
|
### **1.1.4** (2021-06-15)
|
||||||
|
|
||||||
|
- Merge pull request #12 from InseeFrLab/email-typo
|
||||||
|
|
||||||
|
Fix typo on email
|
||||||
|
- Fix typo on email
|
||||||
|
|
||||||
|
### **1.1.3** (2021-06-14)
|
||||||
|
|
||||||
|
- Add missing key in Login for providers
|
||||||
|
|
||||||
|
### **1.1.2** (2021-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### **1.1.1** (2021-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## **1.1.0** (2021-06-14)
|
||||||
|
|
||||||
|
- Add login-idp-link-confirm.ftl
|
||||||
|
- Fix login-update-profile.ftl
|
||||||
|
- Add login-update-profile.ftl page
|
||||||
|
- Fix default background bug
|
||||||
|
- Remove unused 'markdown' dependency
|
||||||
|
- Fix warning related to powerhooks_useGlobalState_kcLanguageTag
|
||||||
|
- Update README.md
|
||||||
|
|
||||||
|
### **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)
|
### **0.0.29** (2021-03-04)
|
||||||
|
|
||||||
- Fix build
|
- Fix build
|
||||||
|
433
README.md
433
README.md
@ -2,98 +2,387 @@
|
|||||||
<img src="https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png">
|
<img src="https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png">
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<i>🔏 Keycloak theme generator for Reacts app 🔏</i>
|
<i>🔏 Create Keycloak themes using React 🔏</i>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<img src="https://github.com/garronej/keycloak-react-theming/workflows/ci/badge.svg?branch=develop">
|
<img src="https://github.com/garronej/keycloakify/workflows/ci/badge.svg?branch=develop">
|
||||||
<img src="https://img.shields.io/bundlephobia/minzip/keycloak-react-theming">
|
<img src="https://img.shields.io/bundlephobia/minzip/keycloakify">
|
||||||
<img src="https://img.shields.io/npm/dw/keycloak-react-theming">
|
<img src="https://img.shields.io/npm/dw/keycloakify">
|
||||||
<img src="https://img.shields.io/npm/l/keycloak-react-theming">
|
<img src="https://img.shields.io/npm/l/keycloakify">
|
||||||
|
<img src="https://camo.githubusercontent.com/0f9fcc0ac1b8617ad4989364f60f78b2d6b32985ad6a508f215f14d8f897b8d3/68747470733a2f2f62616467656e2e6e65742f62616467652f547970655363726970742f7374726963742532302546302539462539322541412f626c7565">
|
||||||
|
<a href="https://github.com/thomasdarimont/awesome-keycloak">
|
||||||
|
<img src="https://awesome.re/mentioned-badge.svg"/>
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<i>Ultimately this build tool generates a Keycloak theme</i>
|
||||||
**!!! This module is under active developement. It is not usable yet!!!**
|
<img src="https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
# Motivations
|
# 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.
|
||||||
|
|
||||||

|
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.
|
Trying to reproduce the look and feel of a specific app in another stack is not an easy task not to mention
|
||||||
On je login/register pages the language is set back to default and the theme is different that the one on the app.
|
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
|
<p align="center">
|
||||||
to reproduce the look and feel of a specific app. Not mentioning the maintenance cost of such an endeavour.
|
<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
|
Wouldn't it be great if we could just design the login and register pages as if they were part of our app?
|
||||||
still letting Keycloak handle the heavy lifting of actually authenticating the users?
|
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.
|
||||||
|
|
||||||
|
If you already have a Keycloak custom theme, it can be easily ported to Keycloakify.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
- [Motivations](#motivations)
|
||||||
|
- [Requirements](#requirements)
|
||||||
|
- [My framework doesn’t 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 doesn’t seem to be supported, what can I do?
|
||||||
|
|
||||||
|
Currently Keycloakify is only compatible with `create-react-app` apps.
|
||||||
|
It doesn’t 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
|
# How to use
|
||||||
|
|
||||||
## Setting up the build tool
|
## 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`
|
```bash
|
||||||
then configure your `package.json` build's script to build the keycloak's theme by adding `&& build-keycloak-theme`.
|
yarn add keycloakify
|
||||||
|
|
||||||
Typically you will get:
|
|
||||||
|
|
||||||
`package.json`:
|
|
||||||
```json
|
|
||||||
"devDependencies": {
|
|
||||||
"keycloak-react-theming": "^0.0.10"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "react-scripts build && build-keycloak-theme"
|
|
||||||
},
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then build your app with `yarn run build` or `npm run build`, you will be provided with instructions
|
[`package.json`](https://github.com/garronej/keycloakify-demo-app/blob/main/package.json)
|
||||||
about how to load the theme into Keycloak.
|
```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 don’t 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:
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[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*
|
||||||
[](https://youtu.be/xTz0Rj7i2v8)
|
[](https://youtu.be/xTz0Rj7i2v8)
|
||||||
|
|
||||||
## Developing your login and register pages in your React app
|
# Email domain whitelist
|
||||||
|
|
||||||
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.
|
||||||
# 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**
|
|
||||||
|
31
package.json
31
package.json
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "keycloak-react-theming",
|
"name": "keycloakify",
|
||||||
"version": "0.0.29",
|
"version": "1.1.6",
|
||||||
"description": "Keycloak theme generator for Reacts app",
|
"description": "Keycloak theme generator for Reacts app",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/garronej/keycloak-react-theming.git"
|
"url": "git://github.com/garronej/keycloakify.git"
|
||||||
},
|
},
|
||||||
"main": "dist/lib/index.js",
|
"main": "dist/lib/index.js",
|
||||||
"types": "dist/lib/index.d.ts",
|
"types": "dist/lib/index.d.ts",
|
||||||
@ -12,15 +12,13 @@
|
|||||||
"clean": "rimraf dist/",
|
"clean": "rimraf dist/",
|
||||||
"build": "yarn clean && tsc && yarn grant-exec-perms && yarn copy-files",
|
"build": "yarn clean && tsc && yarn grant-exec-perms && yarn copy-files",
|
||||||
"grant-exec-perms": "node dist/bin/tools/grant-exec-perms.js",
|
"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",
|
"test": "node dist/test",
|
||||||
"enable_short_import_path": "yarn build && denoify_enable_short_npm_import_path",
|
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml src/**/*.js dist/",
|
||||||
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml dist/",
|
"generate-messages": "node dist/bin/generate-i18n-messages.js"
|
||||||
"generate-messages": "node dist/bin/generate-i18n-messages.js",
|
|
||||||
"watch": "tsc -w"
|
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"build-keycloak-theme": "dist/bin/build-keycloak-theme/index.js",
|
"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",
|
"author": "u/garronej",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -40,23 +38,24 @@
|
|||||||
"login",
|
"login",
|
||||||
"register"
|
"register"
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/garronej/keycloak-react-theming",
|
"homepage": "https://github.com/garronej/keycloakify",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^10.0.0",
|
"@types/node": "^10.0.0",
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"denoify": "^0.6.5",
|
|
||||||
"properties-parser": "^0.3.1",
|
"properties-parser": "^0.3.1",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^4.1.5"
|
"typescript": "^4.2.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scripting-tools": "^0.19.13",
|
|
||||||
"cheerio": "^1.0.0-rc.5",
|
"cheerio": "^1.0.0-rc.5",
|
||||||
"evt": "^1.9.12",
|
"evt": "2.0.0-beta.15",
|
||||||
"minimal-polyfills": "^2.1.6",
|
"minimal-polyfills": "^2.1.6",
|
||||||
"powerhooks": "^0.0.14",
|
"path": "^0.12.7",
|
||||||
"tss-react": "^0.0.9"
|
"powerhooks": "^0.1.0",
|
||||||
|
"react-markdown": "^5.0.3",
|
||||||
|
"scripting-tools": "^0.19.13",
|
||||||
|
"tss-react": "^0.0.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
src/bin/build-keycloak-theme/build-keycloak-theme.ts
Normal file
112
src/bin/build-keycloak-theme/build-keycloak-theme.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { generateKeycloakThemeResources } from "./generateKeycloakThemeResources";
|
||||||
|
import { generateJavaStackFiles } from "./generateJavaStackFiles";
|
||||||
|
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");
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
|
||||||
|
console.log("🔏 Building the keycloak theme...⌚");
|
||||||
|
|
||||||
|
generateKeycloakThemeResources({
|
||||||
|
keycloakThemeBuildingDirPath,
|
||||||
|
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
|
||||||
|
"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({
|
||||||
|
parsedPackageJson,
|
||||||
|
keycloakThemeBuildingDirPath
|
||||||
|
});
|
||||||
|
|
||||||
|
child_process.execSync(
|
||||||
|
"mvn package",
|
||||||
|
{ "cwd": keycloakThemeBuildingDirPath }
|
||||||
|
);
|
||||||
|
|
||||||
|
generateDebugFiles({
|
||||||
|
keycloakThemeBuildingDirPath,
|
||||||
|
"packageJsonName": parsedPackageJson.name
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log([
|
||||||
|
'',
|
||||||
|
`✅ Your keycloak theme has been generated and bundled into ./${pathRelative(reactProjectDirPath, jarFilePath)} 🚀`,
|
||||||
|
`It is to be placed in "/opt/jboss/keycloak/standalone/deployments" in the container running a jboss/keycloak Docker image. (Tested with 11.0.3)`,
|
||||||
|
'',
|
||||||
|
'Using Helm (https://github.com/codecentric/helm-charts), edit to reflect:',
|
||||||
|
'',
|
||||||
|
'value.yaml: ',
|
||||||
|
' extraInitContainers: |',
|
||||||
|
' - name: realm-ext-provider',
|
||||||
|
' image: curlimages/curl',
|
||||||
|
' imagePullPolicy: IfNotPresent',
|
||||||
|
' command:',
|
||||||
|
' - sh',
|
||||||
|
' args:',
|
||||||
|
' - -c',
|
||||||
|
` - curl -L -f -S -o /extensions/${pathBasename(jarFilePath)} https://AN.URL.FOR/${pathBasename(jarFilePath)}`,
|
||||||
|
' volumeMounts:',
|
||||||
|
' - name: extensions',
|
||||||
|
' mountPath: /extensions',
|
||||||
|
' ',
|
||||||
|
' extraVolumeMounts: |',
|
||||||
|
' - name: extensions',
|
||||||
|
' mountPath: /opt/jboss/keycloak/standalone/deployments',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'To test your theme locally, with hot reloading, you can spin up a Keycloak container image with the theme loaded by running:',
|
||||||
|
'',
|
||||||
|
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename))} 👈`,
|
||||||
|
'',
|
||||||
|
'To enable the theme within keycloak log into the admin console ( 👉 http://localhost:8080 username: admin, password: admin 👈), create a realm (called "myrealm" for example),',
|
||||||
|
`go to your realm settings, click on the theme tab then select ${parsedPackageJson.name}.`,
|
||||||
|
`More details: https://www.keycloak.org/getting-started/getting-started-docker`,
|
||||||
|
'',
|
||||||
|
'Once your container is up and configured 👉 http://localhost:8080/auth/realms/myrealm/account 👈',
|
||||||
|
'',
|
||||||
|
].join("\n"));
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { join as pathJoin, dirname as pathDirname, basename as pathBasename } from "path";
|
||||||
|
|
||||||
|
export const containerLaunchScriptBasename = "start_keycloak_testing_container.sh";
|
||||||
|
|
||||||
|
/** Files for being able to run a hot reload keycloak container */
|
||||||
|
export function generateDebugFiles(
|
||||||
|
params: {
|
||||||
|
packageJsonName: string;
|
||||||
|
keycloakThemeBuildingDirPath: string;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
const { packageJsonName, keycloakThemeBuildingDirPath } = params;
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
pathJoin(keycloakThemeBuildingDirPath, "Dockerfile"),
|
||||||
|
Buffer.from(
|
||||||
|
[
|
||||||
|
"FROM jboss/keycloak:11.0.3",
|
||||||
|
"",
|
||||||
|
"USER root",
|
||||||
|
"",
|
||||||
|
"WORKDIR /",
|
||||||
|
"",
|
||||||
|
"ADD configuration /opt/jboss/keycloak/standalone/configuration/",
|
||||||
|
"",
|
||||||
|
'ENTRYPOINT [ "/opt/jboss/tools/docker-entrypoint.sh" ]',
|
||||||
|
].join("\n"),
|
||||||
|
"utf8"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const dockerImage = `${packageJsonName}/keycloak-hot-reload`;
|
||||||
|
const containerName = "keycloak-testing-container";
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename),
|
||||||
|
Buffer.from(
|
||||||
|
[
|
||||||
|
"#!/bin/bash",
|
||||||
|
"",
|
||||||
|
`cd ${keycloakThemeBuildingDirPath}`,
|
||||||
|
"",
|
||||||
|
`docker rm ${containerName} || true`,
|
||||||
|
"",
|
||||||
|
`docker build . -t ${dockerImage}`,
|
||||||
|
"",
|
||||||
|
"docker run \\",
|
||||||
|
" -p 8080:8080 \\",
|
||||||
|
` --name ${containerName} \\`,
|
||||||
|
" -e KEYCLOAK_USER=admin \\",
|
||||||
|
" -e KEYCLOAK_PASSWORD=admin \\",
|
||||||
|
` -v ${pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", packageJsonName)
|
||||||
|
}:/opt/jboss/keycloak/themes/${packageJsonName}:rw \\`,
|
||||||
|
` -it ${dockerImage}:latest`,
|
||||||
|
""
|
||||||
|
].join("\n"),
|
||||||
|
"utf8"
|
||||||
|
),
|
||||||
|
{ "mode": 0o755 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const standaloneHaFilePath = pathJoin(keycloakThemeBuildingDirPath, "configuration", "standalone-ha.xml");
|
||||||
|
|
||||||
|
try { fs.mkdirSync(pathDirname(standaloneHaFilePath)); } catch { }
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
standaloneHaFilePath,
|
||||||
|
fs.readFileSync(pathJoin(__dirname, pathBasename(standaloneHaFilePath)))
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
@ -1,74 +1 @@
|
|||||||
|
export * from "./generateDebugFiles";
|
||||||
import * as fs from "fs";
|
|
||||||
import { join as pathJoin, dirname as pathDirname, basename as pathBasename } from "path";
|
|
||||||
|
|
||||||
export const containerLaunchScriptBasename = "start_keycloak_testing_container.sh";
|
|
||||||
|
|
||||||
/** Files for being able to run a hot reload keycloak container */
|
|
||||||
export function generateDebugFiles(
|
|
||||||
params: {
|
|
||||||
packageJsonName: string;
|
|
||||||
keycloakThemeBuildingDirPath: string;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
|
|
||||||
const { packageJsonName, keycloakThemeBuildingDirPath } = params;
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
pathJoin(keycloakThemeBuildingDirPath, "Dockerfile"),
|
|
||||||
Buffer.from(
|
|
||||||
[
|
|
||||||
"FROM jboss/keycloak:11.0.3",
|
|
||||||
"",
|
|
||||||
"USER root",
|
|
||||||
"",
|
|
||||||
"WORKDIR /",
|
|
||||||
"",
|
|
||||||
"ADD configuration /opt/jboss/keycloak/standalone/configuration/",
|
|
||||||
"",
|
|
||||||
'ENTRYPOINT [ "/opt/jboss/tools/docker-entrypoint.sh" ]',
|
|
||||||
].join("\n"),
|
|
||||||
"utf8"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const dockerImage = `${packageJsonName}/keycloak-hot-reload`;
|
|
||||||
const containerName = "keycloak-testing-container";
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename),
|
|
||||||
Buffer.from(
|
|
||||||
[
|
|
||||||
"#!/bin/bash",
|
|
||||||
"",
|
|
||||||
`cd ${keycloakThemeBuildingDirPath}`,
|
|
||||||
"",
|
|
||||||
`docker rm ${containerName} || true`,
|
|
||||||
"",
|
|
||||||
`docker build . -t ${dockerImage}`,
|
|
||||||
"",
|
|
||||||
"docker run \\",
|
|
||||||
" -p 8080:8080 \\",
|
|
||||||
` --name ${containerName} \\`,
|
|
||||||
" -e KEYCLOAK_USER=admin \\",
|
|
||||||
" -e KEYCLOAK_PASSWORD=admin \\",
|
|
||||||
` -v ${pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", packageJsonName)
|
|
||||||
}:/opt/jboss/keycloak/themes/${packageJsonName}:rw \\`,
|
|
||||||
` -it ${dockerImage}:latest`,
|
|
||||||
""
|
|
||||||
].join("\n"),
|
|
||||||
"utf8"
|
|
||||||
),
|
|
||||||
{ "mode": 0o755 }
|
|
||||||
);
|
|
||||||
|
|
||||||
const standaloneHaFilePath = pathJoin(keycloakThemeBuildingDirPath, "configuration", "standalone-ha.xml");
|
|
||||||
|
|
||||||
try { fs.mkdirSync(pathDirname(standaloneHaFilePath)); } catch { }
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
standaloneHaFilePath,
|
|
||||||
fs.readFileSync(pathJoin(__dirname, pathBasename(standaloneHaFilePath)))
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
var es = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
|
||||||
|
|
||||||
|
var unes = {
|
||||||
|
'&': '&',
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'>': '>',
|
||||||
|
''': "'",
|
||||||
|
''': "'",
|
||||||
|
'"': '"',
|
||||||
|
'"': '"'
|
||||||
|
};
|
||||||
|
var cape = function (m) { return unes[m]; };
|
||||||
|
|
||||||
|
Object.defineProperty(
|
||||||
|
String,
|
||||||
|
"htmlUnescape",
|
||||||
|
{
|
||||||
|
"value": function (un) {
|
||||||
|
return String.prototype.replace.call(un, es, cape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
263
src/bin/build-keycloak-theme/generateFtl/common.ftl
Normal file
263
src/bin/build-keycloak-theme/generateFtl/common.ftl
Normal 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>
|
23
src/bin/build-keycloak-theme/generateFtl/error.ftl
Normal file
23
src/bin/build-keycloak-theme/generateFtl/error.ftl
Normal 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>
|
@ -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>
|
|
193
src/bin/build-keycloak-theme/generateFtl/generateFtl.ts
Normal file
193
src/bin/build-keycloak-theme/generateFtl/generateFtl.ts
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import cheerio from "cheerio";
|
||||||
|
import {
|
||||||
|
replaceImportsFromStaticInJsCode,
|
||||||
|
replaceImportsInInlineCssCode,
|
||||||
|
generateCssCodeToDefineGlobals
|
||||||
|
} from "../replaceImportFromStatic";
|
||||||
|
import fs from "fs";
|
||||||
|
import { join as pathJoin } from "path";
|
||||||
|
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", "login-update-profile.ftl",
|
||||||
|
"login-idp-link-confirm.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: {
|
||||||
|
cssGlobalsToDefine: Record<string, string>;
|
||||||
|
indexHtmlCode: string;
|
||||||
|
urlPathname: string;
|
||||||
|
urlOrigin: undefined | string;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
const { cssGlobalsToDefine, indexHtmlCode, urlPathname, urlOrigin } = params;
|
||||||
|
|
||||||
|
const $ = cheerio.load(indexHtmlCode);
|
||||||
|
|
||||||
|
$("script:not([src])").each((...[, element]) => {
|
||||||
|
|
||||||
|
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"],
|
||||||
|
["script", "src"],
|
||||||
|
] as const).forEach(([selector, attrName]) =>
|
||||||
|
$(selector).each((...[, element]) => {
|
||||||
|
|
||||||
|
const href = $(element).attr(attrName);
|
||||||
|
|
||||||
|
if (href === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(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 ftlCommonPlaceholders = {
|
||||||
|
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': loadFtlFile("common.ftl"),
|
||||||
|
'<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->':
|
||||||
|
[
|
||||||
|
'<#if scripts??>',
|
||||||
|
' <#list scripts as script>',
|
||||||
|
' <script src="${script}" type="text/javascript"></script>',
|
||||||
|
' </#list>',
|
||||||
|
'</#if>'
|
||||||
|
].join("\n")
|
||||||
|
};
|
||||||
|
|
||||||
|
const pageSpecificCodePlaceholder = "<!-- dIddLqMeOedErIdLsPdNdI9dSl42sw -->";
|
||||||
|
|
||||||
|
$("head").prepend(
|
||||||
|
[
|
||||||
|
...(Object.keys(cssGlobalsToDefine).length === 0 ? [] : [
|
||||||
|
'',
|
||||||
|
'<style>',
|
||||||
|
generateCssCodeToDefineGlobals({
|
||||||
|
cssGlobalsToDefine,
|
||||||
|
urlPathname
|
||||||
|
}).cssCodeToPrependInHead,
|
||||||
|
'</style>',
|
||||||
|
''
|
||||||
|
]),
|
||||||
|
...["Object.deepAssign.js", "String.htmlUnescape.js"].map(
|
||||||
|
fileBasename => [
|
||||||
|
"<script>",
|
||||||
|
loadAdjacentFile(fileBasename),
|
||||||
|
"</script>"
|
||||||
|
].join("\n")
|
||||||
|
),
|
||||||
|
'<script>',
|
||||||
|
` window.${ftlValuesGlobalName}= Object.assign(`,
|
||||||
|
` {},`,
|
||||||
|
` ${objectKeys(ftlCommonPlaceholders)[0]}`,
|
||||||
|
' );',
|
||||||
|
'</script>',
|
||||||
|
'',
|
||||||
|
pageSpecificCodePlaceholder,
|
||||||
|
'',
|
||||||
|
objectKeys(ftlCommonPlaceholders)[1]
|
||||||
|
].join("\n"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const partiallyFixedIndexHtmlCode = $.html();
|
||||||
|
|
||||||
|
function generateFtlFilesCode(
|
||||||
|
params: {
|
||||||
|
pageId: PageId;
|
||||||
|
}
|
||||||
|
): { ftlCode: string; } {
|
||||||
|
|
||||||
|
const { pageId } = params;
|
||||||
|
|
||||||
|
const $ = cheerio.load(partiallyFixedIndexHtmlCode);
|
||||||
|
|
||||||
|
const ftlPlaceholders = {
|
||||||
|
'{ "x": "kxOlLqMeOed9sdLdIdOxd444" }': loadFtlFile(pageId),
|
||||||
|
...ftlCommonPlaceholders
|
||||||
|
};
|
||||||
|
|
||||||
|
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]));
|
||||||
|
|
||||||
|
return { ftlCode };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { generateFtlFilesCode };
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,127 +1 @@
|
|||||||
|
export * from "./generateFtl";
|
||||||
|
|
||||||
import cheerio from "cheerio";
|
|
||||||
import {
|
|
||||||
replaceImportFromStaticInJsCode,
|
|
||||||
generateCssCodeToDefineGlobals
|
|
||||||
} from "../replaceImportFromStatic";
|
|
||||||
import fs from "fs";
|
|
||||||
import { join as pathJoin } from "path";
|
|
||||||
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
|
|
||||||
|
|
||||||
export function generateFtlFilesCodeFactory(
|
|
||||||
params: {
|
|
||||||
ftlValuesGlobalName: string;
|
|
||||||
cssGlobalsToDefine: Record<string, string>;
|
|
||||||
indexHtmlCode: string;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
|
|
||||||
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode } = params;
|
|
||||||
|
|
||||||
const $ = cheerio.load(indexHtmlCode);
|
|
||||||
|
|
||||||
$("script:not([src])").each((...[, element]) => {
|
|
||||||
|
|
||||||
const { fixedJsCode } = replaceImportFromStaticInJsCode({
|
|
||||||
ftlValuesGlobalName,
|
|
||||||
"jsCode": $(element).html()!
|
|
||||||
});
|
|
||||||
|
|
||||||
$(element).text(fixedJsCode);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
([
|
|
||||||
["link", "href"],
|
|
||||||
["script", "src"],
|
|
||||||
] as const).forEach(([selector, attrName]) =>
|
|
||||||
$(selector).each((...[, element]) => {
|
|
||||||
|
|
||||||
const href = $(element).attr(attrName);
|
|
||||||
|
|
||||||
if (!href?.startsWith("/")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(element).attr(attrName, "${url.resourcesPath}/build" + href);
|
|
||||||
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
//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],
|
|
||||||
'<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->':
|
|
||||||
[
|
|
||||||
'<#if scripts??>',
|
|
||||||
' <#list scripts as script>',
|
|
||||||
' <script src="${script}" type="text/javascript"></script>',
|
|
||||||
' </#list>',
|
|
||||||
'</#if>',
|
|
||||||
].join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
$("head").prepend(
|
|
||||||
[
|
|
||||||
...(Object.keys(cssGlobalsToDefine).length === 0 ? [] : [
|
|
||||||
'',
|
|
||||||
'<style>',
|
|
||||||
generateCssCodeToDefineGlobals(
|
|
||||||
{ cssGlobalsToDefine }
|
|
||||||
).cssCodeToPrependInHead,
|
|
||||||
'</style>',
|
|
||||||
''
|
|
||||||
]),
|
|
||||||
'<script>',
|
|
||||||
' Object.assign(',
|
|
||||||
` window.${ftlValuesGlobalName},`,
|
|
||||||
` ${objectKeys(ftlPlaceholders)[0]}`,
|
|
||||||
' );',
|
|
||||||
'</script>',
|
|
||||||
'',
|
|
||||||
objectKeys(ftlPlaceholders)[1],
|
|
||||||
''
|
|
||||||
].join("\n"),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const partiallyFixedIndexHtmlCode = $.html();
|
|
||||||
|
|
||||||
function generateFtlFilesCode(
|
|
||||||
params: {
|
|
||||||
pageBasename: "login.ftl" | "register.ftl"
|
|
||||||
}
|
|
||||||
): { ftlCode: string; } {
|
|
||||||
|
|
||||||
const { pageBasename } = params;
|
|
||||||
|
|
||||||
const $ = cheerio.load(partiallyFixedIndexHtmlCode);
|
|
||||||
|
|
||||||
$("head").prepend(
|
|
||||||
[
|
|
||||||
'',
|
|
||||||
'<script>',
|
|
||||||
` window.${ftlValuesGlobalName} = { "pageBasename": "${pageBasename}" };`,
|
|
||||||
'</script>',
|
|
||||||
''
|
|
||||||
].join("\n")
|
|
||||||
);
|
|
||||||
|
|
||||||
let ftlCode = $.html();
|
|
||||||
|
|
||||||
objectKeys(ftlPlaceholders)
|
|
||||||
.forEach(id => ftlCode = ftlCode.replace(id, ftlPlaceholders[id]));
|
|
||||||
|
|
||||||
return { ftlCode };
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return { generateFtlFilesCode };
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
82
src/bin/build-keycloak-theme/generateFtl/info.ftl
Normal file
82
src/bin/build-keycloak-theme/generateFtl/info.ftl
Normal 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>
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>const _=
|
||||||
|
{
|
||||||
|
"idpAlias": (function (){
|
||||||
|
<#attempt>
|
||||||
|
return "${idpAlias}";
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
return "";
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
</script>
|
37
src/bin/build-keycloak-theme/generateFtl/login-otp.ftl
Normal file
37
src/bin/build-keycloak-theme/generateFtl/login-otp.ftl
Normal 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>
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>const _=
|
||||||
|
{
|
||||||
|
"realm": {
|
||||||
|
"loginWithEmailAllowed": (function (){
|
||||||
|
|
||||||
|
<#attempt>
|
||||||
|
return ${realm.loginWithEmailAllowed?c};
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,67 @@
|
|||||||
|
<script>const _=
|
||||||
|
{
|
||||||
|
"user": {
|
||||||
|
"editUsernameAllowed": (function (){
|
||||||
|
<#attempt>
|
||||||
|
return ${user.editUsernameAllowed?c};
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
})(),
|
||||||
|
"username": (function (){
|
||||||
|
<#attempt>
|
||||||
|
return "${user.username!''}" || undefined;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
})(),
|
||||||
|
"email": (function (){
|
||||||
|
<#attempt>
|
||||||
|
return "${user.email!''}" || undefined;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
})(),
|
||||||
|
"firstName": (function (){
|
||||||
|
<#attempt>
|
||||||
|
return "${user.firstName!''}" || undefined;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
})(),
|
||||||
|
"lastName": (function (){
|
||||||
|
<#attempt>
|
||||||
|
return "${user.lastName!''}" || undefined;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
})()
|
||||||
|
},
|
||||||
|
"messagesPerField": {
|
||||||
|
"printIfExists": function (key, x) {
|
||||||
|
switch(key){
|
||||||
|
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>
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
160
src/bin/build-keycloak-theme/generateFtl/login.ftl
Normal file
160
src/bin/build-keycloak-theme/generateFtl/login.ftl
Normal 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>
|
243
src/bin/build-keycloak-theme/generateFtl/register.ftl
Normal file
243
src/bin/build-keycloak-theme/generateFtl/register.ftl
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
<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;
|
||||||
|
|
||||||
|
})(),
|
||||||
|
"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>
|
||||||
|
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -32,7 +32,7 @@ export function generateJavaStackFiles(
|
|||||||
|
|
||||||
return (!homepage ?
|
return (!homepage ?
|
||||||
fallbackGroupId :
|
fallbackGroupId :
|
||||||
url.parse(homepage).host?.split(".").reverse().join(".") ?? fallbackGroupId
|
url.parse(homepage).host?.replace(/:[0-9]+$/,"")?.split(".").reverse().join(".") ?? fallbackGroupId
|
||||||
) + ".keycloak";
|
) + ".keycloak";
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -3,37 +3,56 @@ import { transformCodebase } from "../tools/transformCodebase";
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import {
|
import {
|
||||||
replaceImportFromStaticInCssCode,
|
replaceImportsInCssCode,
|
||||||
replaceImportFromStaticInJsCode
|
replaceImportsFromStaticInJsCode
|
||||||
} from "./replaceImportFromStatic";
|
} from "./replaceImportFromStatic";
|
||||||
import { generateFtlFilesCodeFactory } from "./generateFtl";
|
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
|
||||||
import { keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl } from "../download-sample-keycloak-themes";
|
import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
|
||||||
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
|
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
|
||||||
import * as child_process from "child_process";
|
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(
|
export function generateKeycloakThemeResources(
|
||||||
params: {
|
params: {
|
||||||
themeName: string;
|
themeName: string;
|
||||||
reactAppBuildDirPath: string;
|
reactAppBuildDirPath: string;
|
||||||
keycloakThemeBuildingDirPath: 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");
|
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
|
||||||
|
|
||||||
let allCssGlobalsToDefine: Record<string, string> = {};
|
let allCssGlobalsToDefine: Record<string, string> = {};
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
"destDirPath": pathJoin(themeDirPath, "resources", "build"),
|
"destDirPath":
|
||||||
|
urlOrigin === undefined ?
|
||||||
|
pathJoin(themeDirPath, "resources", "build") :
|
||||||
|
reactAppBuildDirPath,
|
||||||
"srcDirPath": reactAppBuildDirPath,
|
"srcDirPath": reactAppBuildDirPath,
|
||||||
"transformSourceCode": ({ filePath, sourceCode }) => {
|
"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") }
|
{ "cssCode": sourceCode.toString("utf8") }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -48,36 +67,41 @@ export function generateKeycloakThemeResources(
|
|||||||
|
|
||||||
if (/\.js?$/i.test(filePath)) {
|
if (/\.js?$/i.test(filePath)) {
|
||||||
|
|
||||||
const { fixedJsCode } = replaceImportFromStaticInJsCode({
|
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
||||||
"jsCode": sourceCode.toString("utf8"),
|
"jsCode": sourceCode.toString("utf8"),
|
||||||
ftlValuesGlobalName
|
urlOrigin
|
||||||
});
|
});
|
||||||
|
|
||||||
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { "modifiedSourceCode": sourceCode };
|
return urlOrigin === undefined ?
|
||||||
|
{ "modifiedSourceCode": sourceCode } :
|
||||||
|
undefined;
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
|
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
|
||||||
"cssGlobalsToDefine": allCssGlobalsToDefine,
|
"cssGlobalsToDefine": allCssGlobalsToDefine,
|
||||||
ftlValuesGlobalName,
|
|
||||||
"indexHtmlCode": fs.readFileSync(
|
"indexHtmlCode": fs.readFileSync(
|
||||||
pathJoin(reactAppBuildDirPath, "index.html")
|
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(
|
fs.writeFileSync(
|
||||||
pathJoin(themeDirPath, pageBasename),
|
pathJoin(themeDirPath, pageId),
|
||||||
Buffer.from(ftlCode, "utf8")
|
Buffer.from(ftlCode, "utf8")
|
||||||
)
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -86,30 +110,59 @@ export function generateKeycloakThemeResources(
|
|||||||
const tmpDirPath = pathJoin(themeDirPath, "..", "tmp_xxKdLpdIdLd");
|
const tmpDirPath = pathJoin(themeDirPath, "..", "tmp_xxKdLpdIdLd");
|
||||||
|
|
||||||
downloadAndUnzip({
|
downloadAndUnzip({
|
||||||
"url": keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl,
|
"url": builtinThemesUrl,
|
||||||
"destDirPath": tmpDirPath
|
"destDirPath": tmpDirPath
|
||||||
});
|
});
|
||||||
|
|
||||||
transformCodebase({
|
const themeResourcesDirPath = pathJoin(themeDirPath, "resources");
|
||||||
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common"),
|
|
||||||
"destDirPath": pathJoin(tmpDirPath, "..", "common")
|
|
||||||
});
|
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "login", "resources"),
|
"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}`);
|
child_process.execSync(`rm -r ${tmpDirPath}`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
pathJoin(themeDirPath, "theme.properties"),
|
pathJoin(themeDirPath, "theme.properties"),
|
||||||
Buffer.from([
|
Buffer.from("parent=keycloak", "utf8")
|
||||||
`[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")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,81 +1,10 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { generateKeycloakThemeResources } from "./generateKeycloakThemeResources";
|
export * from "./build-keycloak-theme";
|
||||||
import { generateJavaStackFiles } from "./generateJavaStackFiles";
|
import { main } from "./build-keycloak-theme";
|
||||||
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";
|
|
||||||
|
|
||||||
|
|
||||||
const reactProjectDirPath = process.cwd();
|
|
||||||
|
|
||||||
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
|
|
||||||
|
|
||||||
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
|
|
||||||
|
|
||||||
|
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
|
|
||||||
console.log("🔏 Building the keycloak theme...⌚");
|
main();
|
||||||
|
|
||||||
generateKeycloakThemeResources({
|
|
||||||
keycloakThemeBuildingDirPath,
|
|
||||||
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
|
|
||||||
"themeName": parsedPackageJson.name
|
|
||||||
});
|
|
||||||
|
|
||||||
const { jarFilePath } = generateJavaStackFiles({
|
|
||||||
parsedPackageJson,
|
|
||||||
keycloakThemeBuildingDirPath
|
|
||||||
});
|
|
||||||
|
|
||||||
child_process.execSync(
|
|
||||||
"mvn package",
|
|
||||||
{ "cwd": keycloakThemeBuildingDirPath }
|
|
||||||
);
|
|
||||||
|
|
||||||
generateDebugFiles({
|
|
||||||
keycloakThemeBuildingDirPath,
|
|
||||||
"packageJsonName": parsedPackageJson.name
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log([
|
|
||||||
'',
|
|
||||||
`✅ Your keycloak theme has been generated and bundled into ./${pathRelative(reactProjectDirPath, jarFilePath)} 🚀`,
|
|
||||||
`It is to be placed in "/opt/jboss/keycloak/standalone/deployments" in the container running a jboss/keycloak Docker image. (Tested with 11.0.3)`,
|
|
||||||
'',
|
|
||||||
'Using Helm (https://github.com/codecentric/helm-charts), edit to reflect:',
|
|
||||||
'',
|
|
||||||
'value.yaml: ',
|
|
||||||
' extraInitContainers: |',
|
|
||||||
' - name: realm-ext-provider',
|
|
||||||
' image: curlimages/curl',
|
|
||||||
' imagePullPolicy: IfNotPresent',
|
|
||||||
' command:',
|
|
||||||
' - sh',
|
|
||||||
' args:',
|
|
||||||
' - -c',
|
|
||||||
` - curl -L -f -S -o /extensions/${pathBasename(jarFilePath)} https://AN.URL.FOR/${pathBasename(jarFilePath)}`,
|
|
||||||
' volumeMounts:',
|
|
||||||
' - name: extensions',
|
|
||||||
' mountPath: /extensions',
|
|
||||||
' ',
|
|
||||||
' extraVolumeMounts: |',
|
|
||||||
' - name: extensions',
|
|
||||||
' mountPath: /opt/jboss/keycloak/standalone/deployments',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'To test your theme locally, with hot reloading, you can spin up a Keycloak container image with the theme loaded by running:',
|
|
||||||
'',
|
|
||||||
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename))} 👈`,
|
|
||||||
'',
|
|
||||||
'To enable the theme within keycloak log into the admin console ( 👉 http://localhost:8080 username: admin, password: admin 👈), create a realm (called "myrealm" for example),',
|
|
||||||
`go to your realm settings, click on the theme tab then select ${parsedPackageJson.name}.`,
|
|
||||||
`More details: https://www.keycloak.org/getting-started/getting-started-docker`,
|
|
||||||
'',
|
|
||||||
'Once your container is up and configured 👉 http://localhost:8080/auth/realms/myrealm/account 👈',
|
|
||||||
'',
|
|
||||||
].join("\n"));
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,25 +1,52 @@
|
|||||||
|
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
|
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
|
||||||
|
|
||||||
export function replaceImportFromStaticInJsCode(
|
export function replaceImportsFromStaticInJsCode(
|
||||||
params: {
|
params: {
|
||||||
ftlValuesGlobalName: string;
|
|
||||||
jsCode: string;
|
jsCode: string;
|
||||||
|
urlOrigin: undefined | string;
|
||||||
}
|
}
|
||||||
): { fixedJsCode: string; } {
|
): { fixedJsCode: string; } {
|
||||||
|
|
||||||
const { jsCode, ftlValuesGlobalName } = params;
|
const { jsCode, urlOrigin } = params;
|
||||||
|
|
||||||
const fixedJsCode = jsCode!.replace(
|
const fixedJsCode = jsCode.replace(
|
||||||
/"static\//g,
|
/([a-z]+\.[a-z]+)\+"static\//g,
|
||||||
`window.${ftlValuesGlobalName}.url.resourcesPath.replace(/^\\//,"") + "/build/static/`
|
(...[, group]) =>
|
||||||
|
urlOrigin === undefined ?
|
||||||
|
`window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/` :
|
||||||
|
`("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group} + "static/`
|
||||||
);
|
);
|
||||||
|
|
||||||
return { fixedJsCode };
|
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: {
|
params: {
|
||||||
cssCode: string;
|
cssCode: string;
|
||||||
}
|
}
|
||||||
@ -32,7 +59,7 @@ export function replaceImportFromStaticInCssCode(
|
|||||||
|
|
||||||
const cssGlobalsToDefine: Record<string, string> = {};
|
const cssGlobalsToDefine: Record<string, string> = {};
|
||||||
|
|
||||||
new Set(cssCode.match(/(url\(\/[^)]+\))/g) ?? [])
|
new Set(cssCode.match(/url\(\/[^/][^)]+\)[^;}]*/g) ?? [])
|
||||||
.forEach(match =>
|
.forEach(match =>
|
||||||
cssGlobalsToDefine[
|
cssGlobalsToDefine[
|
||||||
"url" + crypto
|
"url" + crypto
|
||||||
@ -60,12 +87,13 @@ export function replaceImportFromStaticInCssCode(
|
|||||||
export function generateCssCodeToDefineGlobals(
|
export function generateCssCodeToDefineGlobals(
|
||||||
params: {
|
params: {
|
||||||
cssGlobalsToDefine: Record<string, string>;
|
cssGlobalsToDefine: Record<string, string>;
|
||||||
|
urlPathname: string;
|
||||||
}
|
}
|
||||||
): {
|
): {
|
||||||
cssCodeToPrependInHead: string;
|
cssCodeToPrependInHead: string;
|
||||||
} {
|
} {
|
||||||
|
|
||||||
const { cssGlobalsToDefine } = params;
|
const { cssGlobalsToDefine, urlPathname } = params;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"cssCodeToPrependInHead": [
|
"cssCodeToPrependInHead": [
|
||||||
@ -73,12 +101,8 @@ export function generateCssCodeToDefineGlobals(
|
|||||||
...Object.keys(cssGlobalsToDefine)
|
...Object.keys(cssGlobalsToDefine)
|
||||||
.map(cssVariableName => [
|
.map(cssVariableName => [
|
||||||
`--${cssVariableName}:`,
|
`--${cssVariableName}:`,
|
||||||
[
|
cssGlobalsToDefine[cssVariableName]
|
||||||
"url(",
|
.replace(new RegExp(`url\\(${urlPathname.replace(/\//g, "\\/")}`, "g"), "url(${url.resourcesPath}/build/")
|
||||||
"${url.resourcesPath}/build" +
|
|
||||||
cssGlobalsToDefine[cssVariableName].match(/^url\(([^)]+)\)$/)![1],
|
|
||||||
")"
|
|
||||||
].join("")
|
|
||||||
].join(" "))
|
].join(" "))
|
||||||
.map(line => ` ${line};`),
|
.map(line => ` ${line};`),
|
||||||
"}"
|
"}"
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import "minimal-polyfills/Object.fromEntries";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { join as pathJoin, relative as pathRelative } from "path";
|
import { join as pathJoin, relative as pathRelative } from "path";
|
||||||
import { crawl } from "./tools/crawl";
|
import { crawl } from "./tools/crawl";
|
||||||
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
|
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 { getProjectRoot } from "./tools/getProjectRoot";
|
||||||
import * as child_process from "child_process";
|
import * as child_process from "child_process";
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ child_process.execSync(`rm -rf ${tmpDirPath}`);
|
|||||||
|
|
||||||
downloadAndUnzip({
|
downloadAndUnzip({
|
||||||
"destDirPath": tmpDirPath,
|
"destDirPath": tmpDirPath,
|
||||||
"url": keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl
|
"url": builtinThemesUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
type Dictionary = { [idiomId: string]: string };
|
type Dictionary = { [idiomId: string]: string };
|
||||||
@ -34,17 +35,21 @@ crawl(".").forEach(filePath => {
|
|||||||
|
|
||||||
const [, typeOfPage, language] = match;
|
const [, typeOfPage, language] = match;
|
||||||
|
|
||||||
(record[typeOfPage] ??= {})[language.replace(/_/g,"-")] =
|
(record[typeOfPage] ??= {})[language.replace(/_/g, "-")] =
|
||||||
propertiesParser.parse(
|
Object.fromEntries(
|
||||||
fs.readFileSync(filePath)
|
Object.entries(
|
||||||
.toString("utf8")
|
propertiesParser.parse(
|
||||||
|
fs.readFileSync(filePath)
|
||||||
|
.toString("utf8")
|
||||||
|
)
|
||||||
|
).map(([key, value]: any) => [key, value.replace(/''/g, "'")])
|
||||||
);
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
child_process.execSync(`rm -r ${tmpDirPath}`);
|
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 });
|
fs.mkdirSync(targetDirPath, { "recursive": true });
|
||||||
|
|
||||||
@ -60,7 +65,7 @@ Object.keys(record).forEach(pageType => {
|
|||||||
'//PLEASE DO NOT EDIT MANUALLY',
|
'//PLEASE DO NOT EDIT MANUALLY',
|
||||||
'',
|
'',
|
||||||
'/* spell-checker: disable */',
|
'/* 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 */'
|
'/* spell-checker: enable */'
|
||||||
].join("\n"), "utf8")
|
].join("\n"), "utf8")
|
||||||
);
|
);
|
||||||
|
@ -4,13 +4,13 @@ import { keycloakThemeBuildingDirPath } from "./build-keycloak-theme";
|
|||||||
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
|
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
|
|
||||||
export const keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl =
|
export const builtinThemesUrl =
|
||||||
"https://github.com/garronej/keycloak-react-theming/releases/download/v0.0.1/other_keycloak_thems.zip";
|
"https://github.com/garronej/keycloakify/releases/download/v0.0.1/keycloak_11.0.3_builtin_themes.zip";
|
||||||
|
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
|
|
||||||
downloadAndUnzip({
|
downloadAndUnzip({
|
||||||
"url": keycloakBuiltinThemesAndThirdPartyExamplesThemsUrl,
|
"url": builtinThemesUrl,
|
||||||
"destDirPath": pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme")
|
"destDirPath": pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme")
|
||||||
});
|
});
|
||||||
|
|
14
src/bin/tools/isInside.ts
Normal file
14
src/bin/tools/isInside.ts
Normal 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("..");
|
||||||
|
|
||||||
|
}
|
39
src/lib/components/Error.tsx
Normal file
39
src/lib/components/Error.tsx
Normal 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>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
72
src/lib/components/Info.tsx
Normal file
72
src/lib/components/Info.tsx
Normal 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>
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -1,25 +1,29 @@
|
|||||||
|
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import { kcContext } from "../kcContext";
|
import type { KcContext } from "../KcContext";
|
||||||
import { assert } from "evt/tools/typeSafety/assert";
|
import type { KcProps } from "./KcProps";
|
||||||
import type { KcPagesProperties } from "./KcProperties";
|
|
||||||
import { Login } from "./Login";
|
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";
|
||||||
|
import { LoginUpdateProfile } from "./LoginUpdateProfile";
|
||||||
|
import { LoginIdpLinkConfirm } from "./LoginIdpLinkConfirm";
|
||||||
|
|
||||||
export type KcAppProps = {
|
export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContext; } & KcProps) => {
|
||||||
kcProperties?: KcPagesProperties;
|
switch (kcContext.pageId) {
|
||||||
};
|
case "login.ftl": return <Login {...{ kcContext, ...props }} />;
|
||||||
|
case "register.ftl": return <Register {...{ kcContext, ...props }} />;
|
||||||
export const KcApp = memo((props: KcAppProps) => {
|
case "info.ftl": return <Info {...{ kcContext, ...props }} />;
|
||||||
|
case "error.ftl": return <Error {...{ kcContext, ...props }} />;
|
||||||
const { kcProperties } = props;
|
case "login-reset-password.ftl": return <LoginResetPassword {...{ kcContext, ...props }} />;
|
||||||
|
case "login-verify-email.ftl": return <LoginVerifyEmail {...{ kcContext, ...props }} />;
|
||||||
assert(kcContext !== undefined, "App is not currently served by a Keycloak server");
|
case "terms.ftl": return <Terms {...{ kcContext, ...props }} />;
|
||||||
|
case "login-otp.ftl": return <LoginOtp {...{ kcContext, ...props }} />;
|
||||||
switch (kcContext.pageBasename) {
|
case "login-update-profile.ftl": return <LoginUpdateProfile {...{ kcContext, ...props }} />;
|
||||||
case "login.ftl": return <Login kcProperties={kcProperties} />
|
case "login-idp-link-confirm.ftl": return <LoginIdpLinkConfirm {...{ kcContext, ...props }} />;
|
||||||
case "register.ftl":
|
|
||||||
alert(`TODO: Implement ${kcContext.pageBasename}`);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
@ -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);
|
|
205
src/lib/components/KcProps.ts
Normal file
205
src/lib/components/KcProps.ts
Normal 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>();
|
||||||
|
|
@ -1,37 +1,21 @@
|
|||||||
|
|
||||||
import { useState, memo } from "react";
|
import { useState, memo } from "react";
|
||||||
import { Template } from "./Template";
|
import { Template } from "./Template";
|
||||||
import type { KcPagesProperties } from "./KcProperties";
|
import type { KcProps } from "./KcProps";
|
||||||
import { defaultKcPagesProperties } from "./KcProperties";
|
import type { KcContext } from "../KcContext";
|
||||||
import { assert } from "evt/tools/typeSafety/assert";
|
import { useKcMessage } from "../i18n/useKcMessage";
|
||||||
import { kcContext } from "../kcContext";
|
|
||||||
import { useKcTranslation } from "../i18n/useKcTranslation";
|
|
||||||
import { cx } from "tss-react";
|
import { cx } from "tss-react";
|
||||||
import { useConstCallback } from "powerhooks";
|
import { useConstCallback } from "powerhooks";
|
||||||
|
|
||||||
export type LoginProps = {
|
export const Login = memo(({ kcContext, ...props }: { kcContext: KcContext.Login; } & KcProps) => {
|
||||||
kcProperties?: KcPagesProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Login = memo((props: LoginProps) => {
|
const { msg, msgStr } = useKcMessage();
|
||||||
|
|
||||||
const { kcProperties = {} } = props;
|
const {
|
||||||
|
|
||||||
const { t, tStr } = useKcTranslation();
|
|
||||||
|
|
||||||
Object.assign(kcProperties, defaultKcPagesProperties);
|
|
||||||
|
|
||||||
const [{
|
|
||||||
social, realm, url,
|
social, realm, url,
|
||||||
usernameEditDisabled, login,
|
usernameEditDisabled, login,
|
||||||
auth, registrationDisabled
|
auth, registrationDisabled
|
||||||
}] = useState(() => (
|
} = kcContext;
|
||||||
assert(
|
|
||||||
kcContext !== undefined,
|
|
||||||
"App is currently being served by keycloak"
|
|
||||||
),
|
|
||||||
kcContext
|
|
||||||
));
|
|
||||||
|
|
||||||
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
|
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
|
||||||
|
|
||||||
@ -39,57 +23,55 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
(setIsLoginButtonDisabled(true), true)
|
(setIsLoginButtonDisabled(true), true)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Template
|
<Template
|
||||||
|
{...{ kcContext, ...props }}
|
||||||
displayInfo={social.displayInfo}
|
displayInfo={social.displayInfo}
|
||||||
displayWide={realm.password && social.providers !== undefined}
|
displayWide={realm.password && social.providers !== undefined}
|
||||||
kcProperties={kcProperties}
|
headerNode={msg("doLogIn")}
|
||||||
headerNode={t("doLogIn")}
|
|
||||||
showUsernameNode={null}
|
|
||||||
formNode={
|
formNode={
|
||||||
<div
|
<div
|
||||||
id="kc-form"
|
id="kc-form"
|
||||||
className={cx(realm.password && social.providers !== undefined && kcProperties.kcContentWrapperClass)}
|
className={cx(realm.password && social.providers !== undefined && props.kcContentWrapperClass)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
id="kc-form-wrapper"
|
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 &&
|
realm.password &&
|
||||||
(
|
(
|
||||||
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
|
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<label htmlFor="username" className={cx(kcProperties.kcLabelClass)}>
|
<label htmlFor="username" className={cx(props.kcLabelClass)}>
|
||||||
{
|
{
|
||||||
!realm.loginWithEmailAllowed ?
|
!realm.loginWithEmailAllowed ?
|
||||||
t("username")
|
msg("username")
|
||||||
:
|
:
|
||||||
(
|
(
|
||||||
!realm.registrationEmailAsUsername ?
|
!realm.registrationEmailAsUsername ?
|
||||||
t("usernameOrEmail") :
|
msg("usernameOrEmail") :
|
||||||
t("email")
|
msg("email")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
id="username"
|
id="username"
|
||||||
className={cx(kcProperties.kcInputClass)}
|
className={cx(props.kcInputClass)}
|
||||||
name="username"
|
name="username"
|
||||||
value={login.username ?? ''}
|
defaultValue={login.username ?? ''}
|
||||||
type="text"
|
type="text"
|
||||||
{...(usernameEditDisabled ? { "disabled": true } : { "autofocus": true, "autocomplete": "off" })}
|
{...(usernameEditDisabled ? { "disabled": true } : { "autoFocus": true, "autoComplete": "off" })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<label htmlFor="password" className={cx(kcProperties.kcLabelClass)}>
|
<label htmlFor="password" className={cx(props.kcLabelClass)}>
|
||||||
{t("password")}
|
{msg("password")}
|
||||||
</label>
|
</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>
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, kcProperties.kcFormSettingClass)}>
|
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
|
||||||
<div id="kc-form-options">
|
<div id="kc-form-options">
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
@ -98,22 +80,23 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
) &&
|
) &&
|
||||||
<div className="checkbox">
|
<div className="checkbox">
|
||||||
<label>
|
<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>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcFormOptionsWrapperClass)}>
|
<div className={cx(props.kcFormOptionsWrapperClass)}>
|
||||||
{
|
{
|
||||||
realm.resetPasswordAllowed &&
|
realm.resetPasswordAllowed &&
|
||||||
<span>
|
<span>
|
||||||
<a tabIndex={5} href={url.loginResetCredentialsUrl}>{t("doForgotPassword")}</a>
|
<a tabIndex={5} href={url.loginResetCredentialsUrl}>{msg("doForgotPassword")}</a>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="kc-form-buttons" className={cx(kcProperties.kcFormGroupClass)}>
|
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
id="id-hidden-input"
|
id="id-hidden-input"
|
||||||
@ -122,8 +105,8 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
tabIndex={4}
|
tabIndex={4}
|
||||||
className={cx(kcProperties.kcButtonClass, kcProperties.kcButtonPrimaryClass, kcProperties.kcButtonBlockClass, kcProperties.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
|
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
|
||||||
value={tStr("doLogIn")}
|
value={msgStr("doLogIn")}
|
||||||
disabled={isLoginButtonDisabled}
|
disabled={isLoginButtonDisabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -133,11 +116,11 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
(realm.password && social.providers !== undefined) &&
|
(realm.password && social.providers !== undefined) &&
|
||||||
<div id="kc-social-providers" className={cx(kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass)}>
|
<div id="kc-social-providers" className={cx(props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass)}>
|
||||||
<ul className={cx(kcProperties.kcFormSocialAccountListClass, social.providers.length > 4 && kcProperties.kcFormSocialAccountDoubleListClass)}>
|
<ul className={cx(props.kcFormSocialAccountListClass, social.providers.length > 4 && props.kcFormSocialAccountDoubleListClass)}>
|
||||||
{
|
{
|
||||||
social.providers.map(p =>
|
social.providers.map(p =>
|
||||||
<li className={cx(kcProperties.kcFormSocialAccountListLinkClass)}>
|
<li key={p.providerId} className={cx(props.kcFormSocialAccountListLinkClass)}>
|
||||||
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
|
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
|
||||||
<span>{p.displayName}</span>
|
<span>{p.displayName}</span>
|
||||||
</a>
|
</a>
|
||||||
@ -149,17 +132,17 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
displayInfoNode={
|
infoNode={
|
||||||
(
|
(
|
||||||
realm.password &&
|
realm.password &&
|
||||||
realm.resetPasswordAllowed &&
|
realm.registrationAllowed &&
|
||||||
!registrationDisabled
|
!registrationDisabled
|
||||||
) &&
|
) &&
|
||||||
<div id="kc-registration">
|
<div id="kc-registration">
|
||||||
<span>
|
<span>
|
||||||
{t("noAccount")}
|
{msg("noAccount")}
|
||||||
<a tabIndex={6} href={url.registrationUrl}>
|
<a tabIndex={6} href={url.registrationUrl}>
|
||||||
{t("doRegister")}
|
{msg("doRegister")}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
58
src/lib/components/LoginIdpLinkConfirm.tsx
Normal file
58
src/lib/components/LoginIdpLinkConfirm.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
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 LoginIdpLinkConfirm = memo(({ kcContext, ...props }: { kcContext: KcContext.LoginIdpLinkConfirm; } & KcProps) => {
|
||||||
|
|
||||||
|
const { msg } = useKcMessage();
|
||||||
|
|
||||||
|
const { url, idpAlias } = kcContext;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Template
|
||||||
|
{...{ kcContext, ...props }}
|
||||||
|
headerNode={msg("confirmLinkIdpTitle")}
|
||||||
|
formNode={
|
||||||
|
<form id="kc-register-form" action={url.loginAction} method="post">
|
||||||
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className={cx(
|
||||||
|
props.kcButtonClass,
|
||||||
|
props.kcButtonDefaultClass,
|
||||||
|
props.kcButtonBlockClass,
|
||||||
|
props.kcButtonLargeClass
|
||||||
|
)}
|
||||||
|
name="submitAction"
|
||||||
|
id="updateProfile"
|
||||||
|
value="updateProfile"
|
||||||
|
>
|
||||||
|
{msg("confirmLinkIdpReviewProfile")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className={cx(
|
||||||
|
props.kcButtonClass,
|
||||||
|
props.kcButtonDefaultClass,
|
||||||
|
props.kcButtonBlockClass,
|
||||||
|
props.kcButtonLargeClass
|
||||||
|
)}
|
||||||
|
name="submitAction"
|
||||||
|
id="linkAccount"
|
||||||
|
value="linkAccount"
|
||||||
|
>
|
||||||
|
{msg("confirmLinkIdpContinue", idpAlias)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
145
src/lib/components/LoginOtp.tsx
Normal file
145
src/lib/components/LoginOtp.tsx
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
80
src/lib/components/LoginResetPassword.tsx
Normal file
80
src/lib/components/LoginResetPassword.tsx
Normal 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")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
130
src/lib/components/LoginUpdateProfile.tsx
Normal file
130
src/lib/components/LoginUpdateProfile.tsx
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
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 LoginUpdateProfile = memo(({ kcContext, ...props }: { kcContext: KcContext.LoginUpdateProfile; } & KcProps) => {
|
||||||
|
|
||||||
|
const { msg, msgStr } = useKcMessage();
|
||||||
|
|
||||||
|
const { url, user, messagesPerField, isAppInitiatedAction } = kcContext;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Template
|
||||||
|
{...{ kcContext, ...props }}
|
||||||
|
headerNode={msg("loginProfileTitle")}
|
||||||
|
formNode={
|
||||||
|
<form id="kc-update-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
|
||||||
|
{user.editUsernameAllowed &&
|
||||||
|
<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"
|
||||||
|
name="username"
|
||||||
|
defaultValue={user.username ?? ""}
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
/>
|
||||||
|
</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"
|
||||||
|
name="email"
|
||||||
|
defaultValue={user.email ?? ""}
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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"
|
||||||
|
name="firstName"
|
||||||
|
defaultValue={user.firstName ?? ""}
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
/>
|
||||||
|
</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"
|
||||||
|
name="lastName"
|
||||||
|
defaultValue={user.lastName ?? ""}
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
/>
|
||||||
|
</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)}>
|
||||||
|
{
|
||||||
|
isAppInitiatedAction ?
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)}
|
||||||
|
type="submit"
|
||||||
|
defaultValue={msgStr("doSubmit")}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)}
|
||||||
|
type="submit"
|
||||||
|
name="cancel-aia"
|
||||||
|
value="true"
|
||||||
|
>
|
||||||
|
{msg("doCancel")}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<input
|
||||||
|
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
|
||||||
|
type="submit"
|
||||||
|
defaultValue={msgStr("doSubmit")}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
38
src/lib/components/LoginVerifyEmail.tsx
Normal file
38
src/lib/components/LoginVerifyEmail.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
123
src/lib/components/Register.tsx
Normal file
123
src/lib/components/Register.tsx
Normal 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 >
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
@ -1,33 +1,31 @@
|
|||||||
|
|
||||||
import { useState, useReducer ,useEffect, memo } from "react";
|
import { useReducer, useEffect, memo } from "react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { useKcTranslation } from "../i18n/useKcTranslation";
|
import { useKcMessage } from "../i18n/useKcMessage";
|
||||||
import { kcContext } from "../kcContext";
|
|
||||||
import { assert } from "evt/tools/typeSafety/assert";
|
|
||||||
import { cx } from "tss-react";
|
|
||||||
import { useKcLanguageTag } from "../i18n/useKcLanguageTag";
|
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 type { KcLanguageTag } from "../i18n/KcLanguageTag";
|
||||||
|
import { getBestMatchAmongKcLanguageTag } from "../i18n/KcLanguageTag";
|
||||||
import { getKcLanguageTagLabel } from "../i18n/KcLanguageTag";
|
import { getKcLanguageTagLabel } from "../i18n/KcLanguageTag";
|
||||||
import { useCallbackFactory } from "powerhooks";
|
import { useCallbackFactory } from "powerhooks";
|
||||||
import { appendHead } from "../tools/appendHead";
|
import { appendHead } from "../tools/appendHead";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import { useConstCallback } from "powerhooks";
|
import { useConstCallback } from "powerhooks";
|
||||||
import type { KcTemplateProperties } from "./KcProperties";
|
import type { KcTemplateProps } from "./KcProps";
|
||||||
import { defaultKcTemplateProperties } from "./KcProperties";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
export type TemplateProps = {
|
||||||
kcProperties: KcTemplateProperties;
|
|
||||||
displayInfo?: boolean;
|
displayInfo?: boolean;
|
||||||
displayMessage?: boolean;
|
displayMessage?: boolean;
|
||||||
displayRequiredFields?: boolean;
|
displayRequiredFields?: boolean;
|
||||||
displayWide?: boolean;
|
displayWide?: boolean;
|
||||||
showAnotherWayIfPresent?: boolean;
|
showAnotherWayIfPresent?: boolean;
|
||||||
headerNode: ReactNode;
|
headerNode: ReactNode;
|
||||||
showUsernameNode: ReactNode;
|
showUsernameNode?: ReactNode;
|
||||||
formNode: ReactNode;
|
formNode: ReactNode;
|
||||||
displayInfoNode: ReactNode;
|
infoNode?: ReactNode;
|
||||||
};
|
} & { kcContext: KcContext; } & KcTemplateProps;
|
||||||
|
|
||||||
|
|
||||||
export const Template = memo((props: TemplateProps) => {
|
export const Template = memo((props: TemplateProps) => {
|
||||||
|
|
||||||
@ -37,47 +35,65 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
displayRequiredFields = false,
|
displayRequiredFields = false,
|
||||||
displayWide = false,
|
displayWide = false,
|
||||||
showAnotherWayIfPresent = true,
|
showAnotherWayIfPresent = true,
|
||||||
kcProperties = {},
|
|
||||||
headerNode,
|
headerNode,
|
||||||
showUsernameNode,
|
showUsernameNode = null,
|
||||||
formNode,
|
formNode,
|
||||||
displayInfoNode
|
infoNode = null,
|
||||||
|
kcContext
|
||||||
} = props;
|
} = 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 { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
|
||||||
|
|
||||||
|
|
||||||
const onChangeLanguageClickFactory = useCallbackFactory(
|
const onChangeLanguageClickFactory = useCallbackFactory(
|
||||||
([languageTag]: [KcLanguageTag]) =>
|
([languageTag]: [KcLanguageTag]) =>
|
||||||
setKcLanguageTag(languageTag)
|
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(locale !== undefined);
|
||||||
assert(kcContext !== undefined, "App is not currently being served by KeyCloak"),
|
|
||||||
kcContext
|
if (kcLanguageTag === getBestMatchAmongKcLanguageTag(locale.current)) {
|
||||||
));
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href =
|
||||||
|
locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
|
||||||
|
|
||||||
|
}, [kcLanguageTag]);
|
||||||
|
|
||||||
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
|
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
let isUnmounted = false;
|
let isUnmounted = false;
|
||||||
|
const cleanups: (() => void)[] = [];
|
||||||
|
|
||||||
|
const toArr = (x: string | readonly string[] | undefined) =>
|
||||||
|
typeof x === "string" ? x.split(" ") : x ?? [];
|
||||||
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
[
|
[
|
||||||
...(kcProperties.stylesCommon ?? []).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
|
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
|
||||||
...(kcProperties.styles ?? []).map(relativePath => pathJoin(url.resourcesPath, relativePath))
|
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath))
|
||||||
].map(href => appendHead({
|
].map(href => appendHead({
|
||||||
"type": "css",
|
"type": "css",
|
||||||
href
|
href
|
||||||
@ -91,36 +107,52 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
kcProperties.scripts?.forEach(
|
toArr(props.scripts).forEach(
|
||||||
relativePath => appendHead({
|
relativePath => appendHead({
|
||||||
"type": "javascript",
|
"type": "javascript",
|
||||||
"src": pathJoin(url.resourcesPath, relativePath)
|
"src": pathJoin(url.resourcesPath, relativePath)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
document.getElementsByTagName("html")[0]
|
if (props.kcHtmlClass !== undefined) {
|
||||||
.classList
|
|
||||||
.add(cx(kcProperties.kcHtmlClass));
|
|
||||||
|
|
||||||
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) {
|
if (!isExtraCssLoaded) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(kcProperties.kcLoginClass)}>
|
<div className={cx(props.kcLoginClass)}>
|
||||||
|
|
||||||
<div id="kc-header" className={cx(kcProperties.kcHeaderClass)}>
|
<div id="kc-header" className={cx(props.kcHeaderClass)}>
|
||||||
<div id="kc-header-wrapper" className={cx(kcProperties.kcHeaderWrapperClass)}>
|
<div id="kc-header-wrapper" className={cx(props.kcHeaderWrapperClass)}>
|
||||||
{t("loginTitleHtml", realm.displayNameHtml)}
|
{msg("loginTitleHtml", realm.displayNameHtml)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormCardClass, displayWide && kcProperties.kcFormCardAccountClass)}>
|
<div className={cx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
|
||||||
<header className={cx(kcProperties.kcFormHeaderClass)}>
|
<header className={cx(props.kcFormHeaderClass)}>
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
realm.internationalizationEnabled &&
|
realm.internationalizationEnabled &&
|
||||||
@ -128,7 +160,7 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
locale.supported.length > 1
|
locale.supported.length > 1
|
||||||
) &&
|
) &&
|
||||||
<div id="kc-locale">
|
<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">
|
<div className="kc-dropdown" id="kc-locale-dropdown">
|
||||||
<a href="#" id="kc-current-locale-link">
|
<a href="#" id="kc-current-locale-link">
|
||||||
{getKcLanguageTagLabel(kcLanguageTag)}
|
{getKcLanguageTagLabel(kcLanguageTag)}
|
||||||
@ -137,14 +169,13 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
{
|
{
|
||||||
locale.supported.map(
|
locale.supported.map(
|
||||||
({ languageTag }) =>
|
({ languageTag }) =>
|
||||||
<li className="kc-dropdown-item">
|
<li key={languageTag} className="kc-dropdown-item">
|
||||||
<a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
|
<a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
|
||||||
{getKcLanguageTagLabel(languageTag)}
|
{getKcLanguageTagLabel(languageTag)}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -162,11 +193,11 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
displayRequiredFields ?
|
displayRequiredFields ?
|
||||||
(
|
(
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcContentWrapperClass)}>
|
<div className={cx(props.kcContentWrapperClass)}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass, "subtitle")}>
|
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
|
||||||
<span className="subtitle">
|
<span className="subtitle">
|
||||||
<span className="required">*</span>
|
<span className="required">*</span>
|
||||||
{t("requiredFields")}
|
{msg("requiredFields")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-10">
|
<div className="col-md-10">
|
||||||
@ -183,19 +214,19 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
displayRequiredFields ? (
|
displayRequiredFields ? (
|
||||||
<div className={cx(kcProperties.kcContentWrapperClass)}>
|
<div className={cx(props.kcContentWrapperClass)}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass, "subtitle")}>
|
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
|
||||||
<span className="subtitle"><span className="required">*</span> {t("requiredFields")}</span>
|
<span className="subtitle"><span className="required">*</span> {msg("requiredFields")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-10">
|
<div className="col-md-10">
|
||||||
{showUsernameNode}
|
{showUsernameNode}
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<div id="kc-username">
|
<div id="kc-username">
|
||||||
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
||||||
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
||||||
<div className="kc-login-tooltip">
|
<div className="kc-login-tooltip">
|
||||||
<i className={cx(kcProperties.kcResetFlowIcon)}></i>
|
<i className={cx(props.kcResetFlowIcon)}></i>
|
||||||
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
|
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -203,21 +234,21 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{showUsernameNode}
|
{showUsernameNode}
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<div id="kc-username">
|
<div id="kc-username">
|
||||||
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
||||||
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
||||||
<div className="kc-login-tooltip">
|
<div className="kc-login-tooltip">
|
||||||
<i className={cx(kcProperties.kcResetFlowIcon)}></i>
|
<i className={cx(props.kcResetFlowIcon)}></i>
|
||||||
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
|
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
)
|
</>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</header>
|
</header>
|
||||||
@ -234,11 +265,14 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
)
|
)
|
||||||
) &&
|
) &&
|
||||||
<div className={cx("alert", `alert-${message.type}`)}>
|
<div className={cx("alert", `alert-${message.type}`)}>
|
||||||
{message.type === "success" && <span className={cx(kcProperties.kcFeedbackSuccessIcon)}></span>}
|
{message.type === "success" && <span className={cx(props.kcFeedbackSuccessIcon)}></span>}
|
||||||
{message.type === "warning" && <span className={cx(kcProperties.kcFeedbackWarningIcon)}></span>}
|
{message.type === "warning" && <span className={cx(props.kcFeedbackWarningIcon)}></span>}
|
||||||
{message.type === "error" && <span className={cx(kcProperties.kcFeedbackErrorIcon)}></span>}
|
{message.type === "error" && <span className={cx(props.kcFeedbackErrorIcon)}></span>}
|
||||||
{message.type === "info" && <span className={cx(kcProperties.kcFeedbackInfoIcon)}></span>}
|
{message.type === "info" && <span className={cx(props.kcFeedbackInfoIcon)}></span>}
|
||||||
<span className="kc-feedback-text">{message.summary}</span>
|
<span
|
||||||
|
className="kc-feedback-text"
|
||||||
|
dangerouslySetInnerHTML={{ "__html": message.summary }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{formNode}
|
{formNode}
|
||||||
@ -249,11 +283,11 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
showAnotherWayIfPresent
|
showAnotherWayIfPresent
|
||||||
) &&
|
) &&
|
||||||
|
|
||||||
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post" className={cx(displayWide && kcProperties.kcContentWrapperClass)} >
|
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post" className={cx(displayWide && props.kcContentWrapperClass)} >
|
||||||
<div className={cx(displayWide && [kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass])} >
|
<div className={cx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])} >
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<input type="hidden" name="tryAnotherWay" value="on" />
|
<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>
|
||||||
</div >
|
</div >
|
||||||
</form>
|
</form>
|
||||||
@ -261,9 +295,9 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
{
|
{
|
||||||
displayInfo &&
|
displayInfo &&
|
||||||
|
|
||||||
<div id="kc-info" className={cx(kcProperties.kcSignUpClass)}>
|
<div id="kc-info" className={cx(props.kcSignUpClass)}>
|
||||||
<div id="kc-info-wrapper" className={cx(kcProperties.kcInfoAreaWrapperClass)}>
|
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}>
|
||||||
{displayInfoNode}
|
{infoNode}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
57
src/lib/components/Terms.tsx
Normal file
57
src/lib/components/Terms.tsx
Normal 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" />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
|||||||
|
|
||||||
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
|
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 =
|
export type LanguageLabel =
|
||||||
/* spell-checker: disable */
|
/* spell-checker: disable */
|
||||||
"Deutsch" | "Norsk" | "Русский" | "Svenska" | "Português (Brasil)" | "Lietuvių" |
|
"Deutsch" | "Norsk" | "Русский" | "Svenska" | "Português (Brasil)" | "Lietuvių" |
|
||||||
"English" | "Italiano" | "Français" | "中文简体" | "Español" | "Čeština" | "日本語" |
|
"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 */
|
/* spell-checker: enable */
|
||||||
|
|
||||||
export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
|
export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
|
||||||
@ -24,16 +24,15 @@ export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
|
|||||||
case "no": return "Norsk";
|
case "no": return "Norsk";
|
||||||
case "pt-BR": return "Português (Brasil)";
|
case "pt-BR": return "Português (Brasil)";
|
||||||
case "ru": return "Русский";
|
case "ru": return "Русский";
|
||||||
case "sk":
|
case "sk": return "Slovenčina";
|
||||||
case "sv": return "Slovenčina";
|
|
||||||
case "ja": return "日本語";
|
case "ja": return "日本語";
|
||||||
case "pl": return "Polish";
|
case "pl": return "Polski";
|
||||||
case "zh-CN": return "中文简体"
|
case "zh-CN": return "中文简体"
|
||||||
case "sv": return "Svenska";
|
case "sv": return "Svenska";
|
||||||
case "lt": return "Lietuvių";
|
case "lt": return "Lietuvių";
|
||||||
case "cs": return "Čeština";
|
case "cs": return "Čeština";
|
||||||
case "nl": return "Nederlands";
|
case "nl": return "Nederlands";
|
||||||
case "tr": return "tr"
|
case "tr": return "Türkçe";
|
||||||
/* spell-checker: enable */
|
/* 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
|
* 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 iso2LanguageLike = languageLike.split("-")[0].toLowerCase();
|
||||||
|
|
||||||
const language = availableLanguages.find(language =>
|
const kcLanguageTag = availableLanguages.find(language =>
|
||||||
language.toLowerCase().includes(iso2LanguageLike) ||
|
language.toLowerCase().includes(iso2LanguageLike) ||
|
||||||
getKcLanguageTagLabel(language).toLocaleLowerCase() === languageLike.toLocaleLowerCase()
|
getKcLanguageTagLabel(language).toLocaleLowerCase() === languageLike.toLocaleLowerCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (language === undefined && languageLike !== navigator.language) {
|
if (kcLanguageTag !== undefined) {
|
||||||
|
return kcLanguageTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (languageLike !== navigator.language) {
|
||||||
return getBestMatchAmongKcLanguageTag(navigator.language);
|
return getBestMatchAmongKcLanguageTag(navigator.language);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//PLEASE DO NOT EDIT MANUALLY
|
//PLEASE DO NOT EDIT MANUALLY
|
||||||
|
|
||||||
/* spell-checker: disable */
|
/* spell-checker: disable */
|
||||||
export const messages= {
|
export const kcMessages= {
|
||||||
"ca": {
|
"ca": {
|
||||||
"doSave": "Desa",
|
"doSave": "Desa",
|
||||||
"doCancel": "Cancel·la",
|
"doCancel": "Cancel·la",
|
||||||
@ -18,7 +18,7 @@ export const messages= {
|
|||||||
"accountManagementTitle": "Gestió de Compte Keycloak",
|
"accountManagementTitle": "Gestió de Compte Keycloak",
|
||||||
"authenticatorTitle": "Autenticador",
|
"authenticatorTitle": "Autenticador",
|
||||||
"applicationsHtmlTitle": "Aplicacions",
|
"applicationsHtmlTitle": "Aplicacions",
|
||||||
"authenticatorCode": "Codi d''un sol ús",
|
"authenticatorCode": "Codi d'un sol ús",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"firstName": "Nom",
|
"firstName": "Nom",
|
||||||
"givenName": "Nom de pila",
|
"givenName": "Nom de pila",
|
||||||
@ -45,11 +45,11 @@ export const messages= {
|
|||||||
"role_view-applications": "Veure aplicacions",
|
"role_view-applications": "Veure aplicacions",
|
||||||
"role_view-clients": "Veure clients",
|
"role_view-clients": "Veure clients",
|
||||||
"role_view-events": "Veure events",
|
"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-realm": "Gestionar domini",
|
||||||
"role_manage-users": "Gestinar usuaris",
|
"role_manage-users": "Gestinar usuaris",
|
||||||
"role_manage-applications": "Gestionar aplicacions",
|
"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-clients": "Gestionar clients",
|
||||||
"role_manage-events": "Gestionar events",
|
"role_manage-events": "Gestionar events",
|
||||||
"role_view-profile": "Veure perfil",
|
"role_view-profile": "Veure perfil",
|
||||||
@ -57,12 +57,12 @@ export const messages= {
|
|||||||
"role_read-token": "Llegir token",
|
"role_read-token": "Llegir token",
|
||||||
"role_offline-access": "Accés sense connexió",
|
"role_offline-access": "Accés sense connexió",
|
||||||
"client_account": "Compte",
|
"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_realm-management": "Gestió de domini",
|
||||||
"client_broker": "Broker",
|
"client_broker": "Broker",
|
||||||
"requiredFields": "Camps obligatoris",
|
"requiredFields": "Camps obligatoris",
|
||||||
"allFieldsRequired": "Tots els camps obligatoris",
|
"allFieldsRequired": "Tots els camps obligatoris",
|
||||||
"backToApplication": "« Torna a l''aplicació",
|
"backToApplication": "« Torna a l'aplicació",
|
||||||
"backTo": "Torna a {0}",
|
"backTo": "Torna a {0}",
|
||||||
"date": "Data",
|
"date": "Data",
|
||||||
"event": "Event",
|
"event": "Event",
|
||||||
@ -87,49 +87,49 @@ export const messages= {
|
|||||||
"action": "Acció",
|
"action": "Acció",
|
||||||
"inResource": "a",
|
"inResource": "a",
|
||||||
"fullAccess": "Accés total",
|
"fullAccess": "Accés total",
|
||||||
"offlineToken": "Codi d''autorització offline",
|
"offlineToken": "Codi d'autorització offline",
|
||||||
"revoke": "Revocar permís",
|
"revoke": "Revocar permís",
|
||||||
"configureAuthenticators": "Autenticadors configurats",
|
"configureAuthenticators": "Autenticadors configurats",
|
||||||
"mobile": "Mòbil",
|
"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.",
|
"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.",
|
"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ó",
|
"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.",
|
"missingUsernameMessage": "Si us plau indica el teu usuari.",
|
||||||
"missingFirstNameMessage": "Si us plau indica el nom.",
|
"missingFirstNameMessage": "Si us plau indica el nom.",
|
||||||
"invalidEmailMessage": "Email no vàlid",
|
"invalidEmailMessage": "Email no vàlid",
|
||||||
"missingLastNameMessage": "Si us plau indica els teus cognoms.",
|
"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.",
|
"missingPasswordMessage": "Si us plau indica la contrasenya.",
|
||||||
"notMatchPasswordMessage": "Les contrasenyes no coincideixen.",
|
"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.",
|
"invalidPasswordExistingMessage": "La contrasenya actual no és correcta.",
|
||||||
"invalidPasswordConfirmMessage": "La confirmació de contrasenya no coincideix.",
|
"invalidPasswordConfirmMessage": "La confirmació de contrasenya no coincideix.",
|
||||||
"invalidTotpMessage": "El código de autenticación no es válido.",
|
"invalidTotpMessage": "El código de autenticación no es válido.",
|
||||||
"usernameExistsMessage": "L''usuari ja existeix",
|
"usernameExistsMessage": "L'usuari ja existeix",
|
||||||
"emailExistsMessage": "L''email ja existeix",
|
"emailExistsMessage": "L'email ja existeix",
|
||||||
"readOnlyUserMessage": "No pots actualitzar el teu usuari perquè el teu compte és de només lectura.",
|
"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.",
|
"readOnlyPasswordMessage": "No pots actualitzar la contrasenya perquè el teu compte és de només lectura.",
|
||||||
"successTotpMessage": "Aplicació d''autenticació mòbil configurada.",
|
"successTotpMessage": "Aplicació d'autenticació mòbil configurada.",
|
||||||
"successTotpRemovedMessage": "Aplicació d''autenticació mòbil eliminada.",
|
"successTotpRemovedMessage": "Aplicació d'autenticació mòbil eliminada.",
|
||||||
"successGrantRevokedMessage": "Permís revocat correctament",
|
"successGrantRevokedMessage": "Permís revocat correctament",
|
||||||
"accountUpdatedMessage": "El teu compte s''ha actualitzat.",
|
"accountUpdatedMessage": "El teu compte s'ha actualitzat.",
|
||||||
"accountPasswordUpdatedMessage": "La contrasenya s''ha actualitzat.",
|
"accountPasswordUpdatedMessage": "La contrasenya s'ha actualitzat.",
|
||||||
"missingIdentityProviderMessage": "Proveïdor d''identitat no indicat.",
|
"missingIdentityProviderMessage": "Proveïdor d'identitat no indicat.",
|
||||||
"invalidFederatedIdentityActionMessage": "Acció no vàlida o no indicada.",
|
"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",
|
"federatedIdentityLinkNotActiveMessage": "Aquesta identitat ja no està activa",
|
||||||
"federatedIdentityRemovingLastProviderMessage": "No pots eliminar l''última identitat federada perquè no tens fixada una contrasenya.",
|
"federatedIdentityRemovingLastProviderMessage": "No pots eliminar l'última identitat federada perquè no tens fixada una contrasenya.",
|
||||||
"identityProviderRedirectErrorMessage": "Error en la redirecció al proveïdor d''identitat",
|
"identityProviderRedirectErrorMessage": "Error en la redirecció al proveïdor d'identitat",
|
||||||
"identityProviderRemovedMessage": "Proveïdor d''identitat esborrat correctament.",
|
"identityProviderRemovedMessage": "Proveïdor d'identitat esborrat correctament.",
|
||||||
"accountDisabledMessage": "El compte està desactivada, contacteu amb l''administrador.",
|
"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.",
|
"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}.",
|
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mínima {0}.",
|
||||||
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
|
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
|
||||||
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
|
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
|
||||||
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
|
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
|
||||||
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
|
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
|
||||||
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d''usuari.",
|
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
|
||||||
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l''expressió regular.",
|
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressió regular.",
|
||||||
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes."
|
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes."
|
||||||
},
|
},
|
||||||
"cs": {
|
"cs": {
|
||||||
@ -571,18 +571,18 @@ export const messages= {
|
|||||||
"missingLastNameMessage": "Please specify last name.",
|
"missingLastNameMessage": "Please specify last name.",
|
||||||
"missingEmailMessage": "Please specify email.",
|
"missingEmailMessage": "Please specify email.",
|
||||||
"missingPasswordMessage": "Please specify password.",
|
"missingPasswordMessage": "Please specify password.",
|
||||||
"notMatchPasswordMessage": "Passwords don''t match.",
|
"notMatchPasswordMessage": "Passwords don't match.",
|
||||||
"invalidUserMessage": "Invalid user",
|
"invalidUserMessage": "Invalid user",
|
||||||
"missingTotpMessage": "Please specify authenticator code.",
|
"missingTotpMessage": "Please specify authenticator code.",
|
||||||
"missingTotpDeviceNameMessage": "Please specify device name.",
|
"missingTotpDeviceNameMessage": "Please specify device name.",
|
||||||
"invalidPasswordExistingMessage": "Invalid existing password.",
|
"invalidPasswordExistingMessage": "Invalid existing password.",
|
||||||
"invalidPasswordConfirmMessage": "Password confirmation doesn''t match.",
|
"invalidPasswordConfirmMessage": "Password confirmation doesn't match.",
|
||||||
"invalidTotpMessage": "Invalid authenticator code.",
|
"invalidTotpMessage": "Invalid authenticator code.",
|
||||||
"usernameExistsMessage": "Username already exists.",
|
"usernameExistsMessage": "Username already exists.",
|
||||||
"emailExistsMessage": "Email already exists.",
|
"emailExistsMessage": "Email already exists.",
|
||||||
"readOnlyUserMessage": "You can''t update your account as it 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.",
|
"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.",
|
"readOnlyPasswordMessage": "You can't update your password as your account is read-only.",
|
||||||
"successTotpMessage": "Mobile authenticator configured.",
|
"successTotpMessage": "Mobile authenticator configured.",
|
||||||
"successTotpRemovedMessage": "Mobile authenticator removed.",
|
"successTotpRemovedMessage": "Mobile authenticator removed.",
|
||||||
"successGrantRevokedMessage": "Grant revoked successfully.",
|
"successGrantRevokedMessage": "Grant revoked successfully.",
|
||||||
@ -592,7 +592,7 @@ export const messages= {
|
|||||||
"invalidFederatedIdentityActionMessage": "Invalid or missing action.",
|
"invalidFederatedIdentityActionMessage": "Invalid or missing action.",
|
||||||
"identityProviderNotFoundMessage": "Specified identity provider not found.",
|
"identityProviderNotFoundMessage": "Specified identity provider not found.",
|
||||||
"federatedIdentityLinkNotActiveMessage": "This identity is not active anymore.",
|
"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.",
|
"identityProviderRedirectErrorMessage": "Failed to redirect to identity provider.",
|
||||||
"identityProviderRemovedMessage": "Identity provider removed successfully.",
|
"identityProviderRemovedMessage": "Identity provider removed successfully.",
|
||||||
"identityProviderAlreadyLinkedMessage": "Federated identity returned by {0} is already linked to another user.",
|
"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).",
|
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
|
||||||
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
|
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
|
||||||
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
|
"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",
|
"myResources": "My Resources",
|
||||||
"myResourcesSub": "My resources",
|
"myResourcesSub": "My resources",
|
||||||
"doDeny": "Deny",
|
"doDeny": "Deny",
|
||||||
@ -915,25 +915,25 @@ export const messages= {
|
|||||||
"role_view-applications": "Voir les applications",
|
"role_view-applications": "Voir les applications",
|
||||||
"role_view-clients": "Voir les clients",
|
"role_view-clients": "Voir les clients",
|
||||||
"role_view-events": "Voir les événements",
|
"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-realm": "Gérer le domaine",
|
||||||
"role_manage-users": "Gérer les utilisateurs",
|
"role_manage-users": "Gérer les utilisateurs",
|
||||||
"role_manage-applications": "Gérer les applications",
|
"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-clients": "Gérer les clients",
|
||||||
"role_manage-events": "Gérer les événements",
|
"role_manage-events": "Gérer les événements",
|
||||||
"role_view-profile": "Voir le profil",
|
"role_view-profile": "Voir le profil",
|
||||||
"role_manage-account": "Gérer le compte",
|
"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",
|
"role_offline-access": "Accès hors-ligne",
|
||||||
"client_account": "Compte",
|
"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_admin-cli": "Admin CLI",
|
||||||
"client_realm-management": "Gestion du domaine",
|
"client_realm-management": "Gestion du domaine",
|
||||||
"client_broker": "Broker",
|
"client_broker": "Broker",
|
||||||
"requiredFields": "Champs obligatoires",
|
"requiredFields": "Champs obligatoires",
|
||||||
"allFieldsRequired": "Tous les champs sont obligatoires",
|
"allFieldsRequired": "Tous les champs sont obligatoires",
|
||||||
"backToApplication": "« Revenir à l''application",
|
"backToApplication": "« Revenir à l'application",
|
||||||
"backTo": "Revenir à {0}",
|
"backTo": "Revenir à {0}",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"event": "Evénement",
|
"event": "Evénement",
|
||||||
@ -958,15 +958,15 @@ export const messages= {
|
|||||||
"action": "Action",
|
"action": "Action",
|
||||||
"inResource": "dans",
|
"inResource": "dans",
|
||||||
"fullAccess": "Accès complet",
|
"fullAccess": "Accès complet",
|
||||||
"offlineToken": "Jeton d''authentification hors-ligne",
|
"offlineToken": "Jeton d'authentification hors-ligne",
|
||||||
"revoke": "Révoquer un droit",
|
"revoke": "Révoquer un droit",
|
||||||
"configureAuthenticators": "Authentifications configurées.",
|
"configureAuthenticators": "Authentifications configurées.",
|
||||||
"mobile": "Téléphone mobile",
|
"mobile": "Téléphone mobile",
|
||||||
"totpStep1": "Installez une des applications suivantes sur votre mobile",
|
"totpStep1": "Installez une des applications suivantes sur votre mobile",
|
||||||
"totpStep2": "Ouvrez l''application et scannez le code-barres ou entrez la clef.",
|
"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.",
|
"totpStep3": "Entrez le code à usage unique fourni par l'application et cliquez sur Sauvegarder pour terminer.",
|
||||||
"totpManualStep2": "Ouvrez l''application et entrez la clef",
|
"totpManualStep2": "Ouvrez l'application et entrez la clef",
|
||||||
"totpManualStep3": "Utilisez les valeurs de configuration suivante si l''application les autorise",
|
"totpManualStep3": "Utilisez les valeurs de configuration suivante si l'application les autorise",
|
||||||
"totpUnableToScan": "Impossible de scanner ?",
|
"totpUnableToScan": "Impossible de scanner ?",
|
||||||
"totpScanBarcode": "Scanner le code-barres ?",
|
"totpScanBarcode": "Scanner le code-barres ?",
|
||||||
"totp.totp": "Basé sur le temps",
|
"totp.totp": "Basé sur le temps",
|
||||||
@ -976,34 +976,34 @@ export const messages= {
|
|||||||
"totpDigits": "Chiffres",
|
"totpDigits": "Chiffres",
|
||||||
"totpInterval": "Intervalle",
|
"totpInterval": "Intervalle",
|
||||||
"totpCounter": "Compteur",
|
"totpCounter": "Compteur",
|
||||||
"missingUsernameMessage": "Veuillez entrer votre nom d''utilisateur.",
|
"missingUsernameMessage": "Veuillez entrer votre nom d'utilisateur.",
|
||||||
"missingFirstNameMessage": "Veuillez entrer votre prénom.",
|
"missingFirstNameMessage": "Veuillez entrer votre prénom.",
|
||||||
"invalidEmailMessage": "Courriel invalide.",
|
"invalidEmailMessage": "Courriel invalide.",
|
||||||
"missingLastNameMessage": "Veuillez entrer votre nom.",
|
"missingLastNameMessage": "Veuillez entrer votre nom.",
|
||||||
"missingEmailMessage": "Veuillez entrer votre courriel.",
|
"missingEmailMessage": "Veuillez entrer votre courriel.",
|
||||||
"missingPasswordMessage": "Veuillez entrer votre mot de passe.",
|
"missingPasswordMessage": "Veuillez entrer votre mot de passe.",
|
||||||
"notMatchPasswordMessage": "Les mots de passe ne sont pas identiques",
|
"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.",
|
"invalidPasswordExistingMessage": "Mot de passe existant invalide.",
|
||||||
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
|
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
|
||||||
"invalidTotpMessage": "Le code d''authentification est invalide.",
|
"invalidTotpMessage": "Le code d'authentification est invalide.",
|
||||||
"usernameExistsMessage": "Le nom d''utilisateur existe déjà.",
|
"usernameExistsMessage": "Le nom d'utilisateur existe déjà.",
|
||||||
"emailExistsMessage": "Le courriel existe déjà.",
|
"emailExistsMessage": "Le courriel existe déjà.",
|
||||||
"readOnlyUserMessage": "Vous ne pouvez pas mettre à jour votre compte car il est en lecture seule.",
|
"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.",
|
"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.",
|
"successTotpMessage": "L'authentification via téléphone mobile est configurée.",
|
||||||
"successTotpRemovedMessage": "L''authentification via téléphone mobile est supprimée.",
|
"successTotpRemovedMessage": "L'authentification via téléphone mobile est supprimée.",
|
||||||
"successGrantRevokedMessage": "Droit révoqué avec succès.",
|
"successGrantRevokedMessage": "Droit révoqué avec succès.",
|
||||||
"accountUpdatedMessage": "Votre compte a été mis à jour.",
|
"accountUpdatedMessage": "Votre compte a été mis à jour.",
|
||||||
"accountPasswordUpdatedMessage": "Votre mot de passe 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.",
|
"invalidFederatedIdentityActionMessage": "Action manquante ou invalide.",
|
||||||
"identityProviderNotFoundMessage": "Le fournisseur d''identité spécifié n''est pas trouvé.",
|
"identityProviderNotFoundMessage": "Le fournisseur d'identité spécifié n'est pas trouvé.",
|
||||||
"federatedIdentityLinkNotActiveMessage": "Cette identité n''est plus active dorénavant.",
|
"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é.",
|
"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é.",
|
"identityProviderRedirectErrorMessage": "Erreur de redirection vers le fournisseur d'identité.",
|
||||||
"identityProviderRemovedMessage": "Le fournisseur d''identité a été supprimé correctement.",
|
"identityProviderRemovedMessage": "Le fournisseur d'identité a été supprimé correctement.",
|
||||||
"identityProviderAlreadyLinkedMessage": "Le fournisseur d''identité retourné par {0} est déjà lié à un autre utilisateur.",
|
"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.",
|
"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.",
|
"accountTemporarilyDisabledMessage": "Ce compte est temporairement désactivé, veuillez contacter votre administrateur ou réessayez plus tard.",
|
||||||
"invalidPasswordMinLengthMessage": "Mot de passe invalide: longueur minimale {0}.",
|
"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).",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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."
|
"invalidPasswordHistoryMessage": "Mot de passe invalide: ne doit pas être égal aux {0} derniers mots de passe."
|
||||||
},
|
},
|
||||||
"it": {
|
"it": {
|
||||||
@ -1027,7 +1027,7 @@ export const messages= {
|
|||||||
"editAccountHtmlTitle": "Modifica Account",
|
"editAccountHtmlTitle": "Modifica Account",
|
||||||
"personalInfoHtmlTitle": "Informazioni personali",
|
"personalInfoHtmlTitle": "Informazioni personali",
|
||||||
"federatedIdentitiesHtmlTitle": "Identità federate",
|
"federatedIdentitiesHtmlTitle": "Identità federate",
|
||||||
"accountLogHtmlTitle": "Log dell''account",
|
"accountLogHtmlTitle": "Log dell'account",
|
||||||
"changePasswordHtmlTitle": "Cambia password",
|
"changePasswordHtmlTitle": "Cambia password",
|
||||||
"deviceActivityHtmlTitle": "Attività dei dispositivi",
|
"deviceActivityHtmlTitle": "Attività dei dispositivi",
|
||||||
"sessionsHtmlTitle": "Sessioni",
|
"sessionsHtmlTitle": "Sessioni",
|
||||||
@ -1037,9 +1037,9 @@ export const messages= {
|
|||||||
"linkedAccountsHtmlTitle": "Account collegati",
|
"linkedAccountsHtmlTitle": "Account collegati",
|
||||||
"accountManagementWelcomeMessage": "Benvenuto nella gestione degli account di Keycloak",
|
"accountManagementWelcomeMessage": "Benvenuto nella gestione degli account di Keycloak",
|
||||||
"personalInfoIntroMessage": "Gestisci le tue informazioni di base",
|
"personalInfoIntroMessage": "Gestisci le tue informazioni di base",
|
||||||
"accountSecurityTitle": "Sicurezza dell''account",
|
"accountSecurityTitle": "Sicurezza dell'account",
|
||||||
"accountSecurityIntroMessage": "Controlla la tua password e gli accessi 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",
|
"applicationsIntroMessage": "Traccia e gestisci i permessi delle applicazioni nell'accesso al tuo account",
|
||||||
"resourceIntroMessage": "Condividi le tue risorse tra i membri del team",
|
"resourceIntroMessage": "Condividi le tue risorse tra i membri del team",
|
||||||
"passwordLastUpdateMessage": "La tua password è stata aggiornata il",
|
"passwordLastUpdateMessage": "La tua password è stata aggiornata il",
|
||||||
"updatePasswordTitle": "Aggiornamento password",
|
"updatePasswordTitle": "Aggiornamento password",
|
||||||
@ -1092,7 +1092,7 @@ export const messages= {
|
|||||||
"role_manage-events": "Gestisci eventi",
|
"role_manage-events": "Gestisci eventi",
|
||||||
"role_view-profile": "Visualizza profilo",
|
"role_view-profile": "Visualizza profilo",
|
||||||
"role_manage-account": "Gestisci account",
|
"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_manage-consent": "Gestisci consensi",
|
||||||
"role_read-token": "Leggi token",
|
"role_read-token": "Leggi token",
|
||||||
"role_offline-access": "Accesso offline",
|
"role_offline-access": "Accesso offline",
|
||||||
@ -1105,7 +1105,7 @@ export const messages= {
|
|||||||
"client_broker": "Broker",
|
"client_broker": "Broker",
|
||||||
"requiredFields": "Campi obbligatori",
|
"requiredFields": "Campi obbligatori",
|
||||||
"allFieldsRequired": "Tutti campi obbligatori",
|
"allFieldsRequired": "Tutti campi obbligatori",
|
||||||
"backToApplication": "« Torna all''applicazione",
|
"backToApplication": "« Torna all'applicazione",
|
||||||
"backTo": "Torna a {0}",
|
"backTo": "Torna a {0}",
|
||||||
"date": "Data",
|
"date": "Data",
|
||||||
"event": "Evento",
|
"event": "Evento",
|
||||||
@ -1136,14 +1136,14 @@ export const messages= {
|
|||||||
"configureAuthenticators": "Autenticatori configurati",
|
"configureAuthenticators": "Autenticatori configurati",
|
||||||
"mobile": "Dispositivo mobile",
|
"mobile": "Dispositivo mobile",
|
||||||
"totpStep1": "Installa una delle seguenti applicazioni sul tuo dispositivo mobile",
|
"totpStep1": "Installa una delle seguenti applicazioni sul tuo dispositivo mobile",
|
||||||
"totpStep2": "Apri l''applicazione e scansiona il codice QR",
|
"totpStep2": "Apri l'applicazione e scansiona il codice QR",
|
||||||
"totpStep3": "Scrivi il codice monouso fornito dall''applicazione e clicca Salva per completare il setup.",
|
"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.",
|
"totpStep3DeviceName": "Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione.",
|
||||||
"totpManualStep2": "Apri l''applicazione e scrivi la chiave",
|
"totpManualStep2": "Apri l'applicazione e scrivi la chiave",
|
||||||
"totpManualStep3": "Usa le seguenti impostazioni se l''applicazione lo consente",
|
"totpManualStep3": "Usa le seguenti impostazioni se l'applicazione lo consente",
|
||||||
"totpUnableToScan": "Non riesci a scansionare il codice QR?",
|
"totpUnableToScan": "Non riesci a scansionare il codice QR?",
|
||||||
"totpScanBarcode": "Vuoi 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",
|
"totp.hotp": "Basato sul contatore",
|
||||||
"totpType": "Tipo",
|
"totpType": "Tipo",
|
||||||
"totpAlgorithm": "Algoritmo",
|
"totpAlgorithm": "Algoritmo",
|
||||||
@ -1155,7 +1155,7 @@ export const messages= {
|
|||||||
"missingFirstNameMessage": "Inserisci il nome.",
|
"missingFirstNameMessage": "Inserisci il nome.",
|
||||||
"invalidEmailMessage": "Indirizzo email non valido.",
|
"invalidEmailMessage": "Indirizzo email non valido.",
|
||||||
"missingLastNameMessage": "Inserisci il cognome.",
|
"missingLastNameMessage": "Inserisci il cognome.",
|
||||||
"missingEmailMessage": "Inserisci l''indirizzo email.",
|
"missingEmailMessage": "Inserisci l'indirizzo email.",
|
||||||
"missingPasswordMessage": "Inserisci la password.",
|
"missingPasswordMessage": "Inserisci la password.",
|
||||||
"notMatchPasswordMessage": "Le password non coincidono.",
|
"notMatchPasswordMessage": "Le password non coincidono.",
|
||||||
"invalidUserMessage": "Utente non valido",
|
"invalidUserMessage": "Utente non valido",
|
||||||
@ -1176,16 +1176,16 @@ export const messages= {
|
|||||||
"accountPasswordUpdatedMessage": "La tua password è stata aggiornata.",
|
"accountPasswordUpdatedMessage": "La tua password è stata aggiornata.",
|
||||||
"missingIdentityProviderMessage": "Identity provider non specificato.",
|
"missingIdentityProviderMessage": "Identity provider non specificato.",
|
||||||
"invalidFederatedIdentityActionMessage": "Azione non valida o mancante.",
|
"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.",
|
"federatedIdentityLinkNotActiveMessage": "Questo identity non è più attivo.",
|
||||||
"federatedIdentityRemovingLastProviderMessage": "Non puoi rimuovere l''ultima identità federata poiché non hai più la password.",
|
"federatedIdentityRemovingLastProviderMessage": "Non puoi rimuovere l'ultima identità federata poiché non hai più la password.",
|
||||||
"identityProviderRedirectErrorMessage": "Il reindirizzamento all''identity provider è fallito.",
|
"identityProviderRedirectErrorMessage": "Il reindirizzamento all'identity provider è fallito.",
|
||||||
"identityProviderRemovedMessage": "Identity provider eliminato correttamente.",
|
"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.",
|
"staleCodeAccountMessage": "La pagina è scaduta. Prova di nuovo.",
|
||||||
"consentDenied": "Consenso negato.",
|
"consentDenied": "Consenso negato.",
|
||||||
"accountDisabledMessage": "Account disabilitato, contatta l''amministratore.",
|
"accountDisabledMessage": "Account disabilitato, contatta l'amministratore.",
|
||||||
"accountTemporarilyDisabledMessage": "L''account è temporaneamente disabilitato, contatta l''amministratore o riprova più tardi.",
|
"accountTemporarilyDisabledMessage": "L'account è temporaneamente disabilitato, contatta l'amministratore o riprova più tardi.",
|
||||||
"invalidPasswordMinLengthMessage": "Password non valida: lunghezza minima {0}.",
|
"invalidPasswordMinLengthMessage": "Password non valida: lunghezza minima {0}.",
|
||||||
"invalidPasswordMinLowerCaseCharsMessage": "Password non valida: deve contenere almeno {0} caratteri minuscoli.",
|
"invalidPasswordMinLowerCaseCharsMessage": "Password non valida: deve contenere almeno {0} caratteri minuscoli.",
|
||||||
"invalidPasswordMinDigitsMessage": "Password non valida: deve contenere almeno {0} numeri.",
|
"invalidPasswordMinDigitsMessage": "Password non valida: deve contenere almeno {0} numeri.",
|
||||||
@ -1246,20 +1246,20 @@ export const messages= {
|
|||||||
"identityProvider": "Identity provider",
|
"identityProvider": "Identity provider",
|
||||||
"identityProviderMessage": "Collegare il tuo account con gli identity provider che hai configurato",
|
"identityProviderMessage": "Collegare il tuo account con gli identity provider che hai configurato",
|
||||||
"socialLogin": "Social Login",
|
"socialLogin": "Social Login",
|
||||||
"userDefined": "Definito dall''utente",
|
"userDefined": "Definito dall'utente",
|
||||||
"removeAccess": "Rimuovi accesso",
|
"removeAccess": "Rimuovi accesso",
|
||||||
"removeAccessMessage": "Devi concedere di nuovo l''accesso, se vuoi utilizzare l''account di questa applicazione.",
|
"removeAccessMessage": "Devi concedere di nuovo l'accesso, se vuoi utilizzare l'account di questa applicazione.",
|
||||||
"authenticatorStatusMessage": "L''autenticazione a due fattori è attualmente",
|
"authenticatorStatusMessage": "L'autenticazione a due fattori è attualmente",
|
||||||
"authenticatorFinishSetUpTitle": "La tua autenticazione a due fattori",
|
"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.",
|
"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",
|
"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.",
|
"authenticatorSubMessage": "Per incrementare la sicurezza del tuo account, attiva almeno uno dei metodi disponibili per l'autenticazione a due fattori.",
|
||||||
"authenticatorMobileTitle": "Autenticatore mobile",
|
"authenticatorMobileTitle": "Autenticatore mobile",
|
||||||
"authenticatorMobileMessage": "Utilizza l''autenticatore mobile per ottenere i codici di verifica per l''autenticazione a due fattori.",
|
"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.",
|
"authenticatorMobileFinishSetUpMessage": "L'autenticatore è stato collegato al tuo telefono.",
|
||||||
"authenticatorActionSetup": "Set up",
|
"authenticatorActionSetup": "Set up",
|
||||||
"authenticatorSMSTitle": "Codice SMS",
|
"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",
|
"authenticatorSMSFinishSetUpMessage": "I messaggi di testo vengono inviati a",
|
||||||
"authenticatorDefaultStatus": "Default",
|
"authenticatorDefaultStatus": "Default",
|
||||||
"authenticatorChangePhone": "Cambia numero di telefono",
|
"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.",
|
"authenticatorBackupCodesFinishSetUpMessage": "Sono stati generati dodici codici di backup. Ognuno può essere usato una sola volta.",
|
||||||
"authenticatorMobileSetupTitle": "Setup autenticatore mobile",
|
"authenticatorMobileSetupTitle": "Setup autenticatore mobile",
|
||||||
"smscodeIntroMessage": "Inserisci il tuo numero di telefono e ti verrà inviato un codice di verifica.",
|
"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.",
|
"mobileSetupStep1": "Installa un'applicazione di autenticazione sul tuo telefono. Sono supportate le applicazioni qui elencate.",
|
||||||
"mobileSetupStep2": "Apri l''applicazione e scansiona il codice QR:",
|
"mobileSetupStep2": "Apri l'applicazione e scansiona il codice QR:",
|
||||||
"mobileSetupStep3": "Inserisci il codice monouso fornito dall''applicazione e clicca Salva per completare il setup.",
|
"mobileSetupStep3": "Inserisci il codice monouso fornito dall'applicazione e clicca Salva per completare il setup.",
|
||||||
"scanBarCode": "Vuoi scansionare il codice QR?",
|
"scanBarCode": "Vuoi scansionare il codice QR?",
|
||||||
"enterBarCode": "Inserisci il codice monouso",
|
"enterBarCode": "Inserisci il codice monouso",
|
||||||
"doCopy": "Copia",
|
"doCopy": "Copia",
|
||||||
@ -1289,7 +1289,7 @@ export const messages= {
|
|||||||
"backupCodesTips-2": "Questi codici sono stati generati il",
|
"backupCodesTips-2": "Questi codici sono stati generati il",
|
||||||
"generateNewBackupCodes": "Genera dei nuovi codici di backup",
|
"generateNewBackupCodes": "Genera dei nuovi codici di backup",
|
||||||
"backupCodesTips-3": "Quando generi dei nuovi codici di backup, quelli attuali non funzioneranno più.",
|
"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",
|
"resources": "Risorse",
|
||||||
"sharedwithMe": "Condiviso con me",
|
"sharedwithMe": "Condiviso con me",
|
||||||
"share": "Condiviso",
|
"share": "Condiviso",
|
||||||
@ -1307,10 +1307,10 @@ export const messages= {
|
|||||||
"addPeople": "Aggiungi persone con le quali condividere la tua risorsa",
|
"addPeople": "Aggiungi persone con le quali condividere la tua risorsa",
|
||||||
"addTeam": "Aggiungi gruppi con i quali condividere la tua risorsa",
|
"addTeam": "Aggiungi gruppi con i quali condividere la tua risorsa",
|
||||||
"myPermissions": "Miei permessi",
|
"myPermissions": "Miei permessi",
|
||||||
"waitingforApproval": "Attesa dell''approvazione",
|
"waitingforApproval": "Attesa dell'approvazione",
|
||||||
"anyPermission": "Qualsiasi permesso",
|
"anyPermission": "Qualsiasi permesso",
|
||||||
"openshift.scope.user_info": "Informazioni utente",
|
"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.user_full": "Accesso completo",
|
||||||
"openshift.scope.list-projects": "Elenca progetti"
|
"openshift.scope.list-projects": "Elenca progetti"
|
||||||
},
|
},
|
||||||
@ -2734,7 +2734,7 @@ export const messages= {
|
|||||||
"mobile": "Mobil",
|
"mobile": "Mobil",
|
||||||
"totpStep1": "Akıllı Telefonunuza aşağıdaki uygulamalardan birini yükleyin:",
|
"totpStep1": "Akıllı Telefonunuza aşağıdaki uygulamalardan birini yükleyin:",
|
||||||
"totpStep2": "Uygulamayı açın ve barkodu okutun.",
|
"totpStep2": "Uygulamayı açı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ı açın ve aşağıdaki anahtarı girin.",
|
"totpManualStep2": "Uygulamayı açın ve aşağıdaki anahtarı girin.",
|
||||||
"totpManualStep3": "Bunları uygulama için özelleştirebilirseniz aşağıdaki yapılandırma değerlerini kullanın:",
|
"totpManualStep3": "Bunları uygulama için özelleştirebilirseniz aşağıdaki yapılandırma değerlerini kullanın:",
|
||||||
"totpUnableToScan": "Barkodu tarayamıyor musunuz?",
|
"totpUnableToScan": "Barkodu tarayamıyor musunuz?",
|
||||||
@ -2858,7 +2858,7 @@ export const messages= {
|
|||||||
"authenticatorSubTitle": "İki Faktörlü Kimlik Doğrulamayı Ayarlama",
|
"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.",
|
"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ı",
|
"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ı.",
|
"authenticatorMobileFinishSetUpMessage": "Doğrulayıcı, telefonunuza bağlı.",
|
||||||
"authenticatorActionSetup": "Kur",
|
"authenticatorActionSetup": "Kur",
|
||||||
"authenticatorSMSTitle": "SMS Kodu",
|
"authenticatorSMSTitle": "SMS Kodu",
|
||||||
@ -2873,7 +2873,7 @@ export const messages= {
|
|||||||
"smscodeIntroMessage": "Telefon numaranızı girin ve telefonunuza bir doğrulama kodu gönderilecektir.",
|
"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.",
|
"mobileSetupStep1": "Telefonunuza bir kimlik doğrulama uygulaması yükleyin. Burada listelenen uygulamalar desteklenmektedir.",
|
||||||
"mobileSetupStep2": "Uygulamayı açın ve barkodu tarayın.",
|
"mobileSetupStep2": "Uygulamayı açı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?",
|
"scanBarCode": "Barkodu taramak ister misiniz?",
|
||||||
"enterBarCode": "Tek seferlik kodu girin",
|
"enterBarCode": "Tek seferlik kodu girin",
|
||||||
"doCopy": "Kopyala",
|
"doCopy": "Kopyala",
|
||||||
@ -3060,5 +3060,5 @@ export const messages= {
|
|||||||
"locale_ru": "Русский",
|
"locale_ru": "Русский",
|
||||||
"locale_zh-CN": "中文简体"
|
"locale_zh-CN": "中文简体"
|
||||||
}
|
}
|
||||||
} as const;
|
};
|
||||||
/* spell-checker: enable */
|
/* spell-checker: enable */
|
@ -2,7 +2,7 @@
|
|||||||
//PLEASE DO NOT EDIT MANUALLY
|
//PLEASE DO NOT EDIT MANUALLY
|
||||||
|
|
||||||
/* spell-checker: disable */
|
/* spell-checker: disable */
|
||||||
export const messages= {
|
export const kcMessages= {
|
||||||
"ca": {
|
"ca": {
|
||||||
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes.",
|
"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.",
|
"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.",
|
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
|
||||||
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
|
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
|
||||||
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
|
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
|
||||||
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d''usuari.",
|
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
|
||||||
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l''expressió regular."
|
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressió regular."
|
||||||
},
|
},
|
||||||
"de": {
|
"de": {
|
||||||
"invalidPasswordMinLengthMessage": "Ungültiges Passwort: muss mindestens {0} Zeichen beinhalten.",
|
"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).",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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."
|
"invalidPasswordHistoryMessage": "Mot de passe invalide : ne doit pas être égal aux {0} derniers mot de passe."
|
||||||
},
|
},
|
||||||
"it": {},
|
"it": {},
|
||||||
@ -240,5 +240,5 @@ export const messages= {
|
|||||||
"pairwiseFailedToGetRedirectURIs": "无法从服务器获得重定向URL",
|
"pairwiseFailedToGetRedirectURIs": "无法从服务器获得重定向URL",
|
||||||
"pairwiseRedirectURIsMismatch": "客户端的重定向URI与服务器端获取的URI配置不匹配。"
|
"pairwiseRedirectURIsMismatch": "客户端的重定向URI与服务器端获取的URI配置不匹配。"
|
||||||
}
|
}
|
||||||
} as const;
|
};
|
||||||
/* spell-checker: enable */
|
/* spell-checker: enable */
|
@ -2,29 +2,29 @@
|
|||||||
//PLEASE DO NOT EDIT MANUALLY
|
//PLEASE DO NOT EDIT MANUALLY
|
||||||
|
|
||||||
/* spell-checker: disable */
|
/* spell-checker: disable */
|
||||||
export const messages= {
|
export const kcMessages= {
|
||||||
"ca": {
|
"ca": {
|
||||||
"emailVerificationSubject": "Verificació d''email",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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ó",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>"
|
"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": {
|
"cs": {
|
||||||
"emailVerificationSubject": "Ověření e-mailu",
|
"emailVerificationSubject": "Ověření e-mailu",
|
||||||
@ -108,17 +108,17 @@ export const messages= {
|
|||||||
},
|
},
|
||||||
"en": {
|
"en": {
|
||||||
"emailVerificationSubject": "Verify email",
|
"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.",
|
"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>",
|
"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",
|
"emailTestSubject": "[KEYCLOAK] - SMTP test message",
|
||||||
"emailTestBody": "This is a test message",
|
"emailTestBody": "This is a test message",
|
||||||
"emailTestBodyHtml": "<p>This is a test message</p>",
|
"emailTestBodyHtml": "<p>This is a test message</p>",
|
||||||
"identityProviderLinkSubject": "Link {0}",
|
"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}.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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": {
|
"fr": {
|
||||||
"emailVerificationSubject": "Vérification du courriel",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>"
|
"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": {
|
"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.",
|
"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>",
|
"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",
|
"emailTestSubject": "[KEYCLOAK] - messaggio di test SMTP",
|
||||||
"emailTestBody": "Questo è un messaggio di test",
|
"emailTestBody": "Questo è un messaggio di test",
|
||||||
"emailTestBodyHtml": "<p>Questo è un messaggio di test</p>",
|
"emailTestBodyHtml": "<p>Questo è un messaggio di test</p>",
|
||||||
"identityProviderLinkSubject": "Link {0}",
|
"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}.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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)",
|
"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.",
|
"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>",
|
"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",
|
"eventUpdatePasswordSubject": "Aggiornamento password",
|
||||||
"eventUpdatePasswordBody": "La tua password è stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l''amministratore.",
|
"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>",
|
"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)",
|
"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.",
|
"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>",
|
"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.CONFIGURE_TOTP": "Configurazione OTP",
|
||||||
"requiredAction.terms_and_conditions": "Termini e condizioni",
|
"requiredAction.terms_and_conditions": "Termini e condizioni",
|
||||||
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
|
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
|
||||||
"requiredAction.UPDATE_PROFILE": "Aggiornamento profilo",
|
"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": "secondi",
|
||||||
"linkExpirationFormatter.timePeriodUnit.seconds.1": "secondo",
|
"linkExpirationFormatter.timePeriodUnit.seconds.1": "secondo",
|
||||||
"linkExpirationFormatter.timePeriodUnit.minutes": "minuti",
|
"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.",
|
"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>",
|
"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ı",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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",
|
"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.",
|
"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>",
|
"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.",
|
"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>",
|
"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.terms_and_conditions": "Şartlar ve Koşullar",
|
||||||
"requiredAction.UPDATE_PASSWORD": "Şifre Güncelleme",
|
"requiredAction.UPDATE_PASSWORD": "Şifre Güncelleme",
|
||||||
"requiredAction.UPDATE_PROFILE": "Profilleri güncelle",
|
"requiredAction.UPDATE_PROFILE": "Profilleri güncelle",
|
||||||
@ -634,5 +634,5 @@ export const messages= {
|
|||||||
"eventUpdateTotpBody": "您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。",
|
"eventUpdateTotpBody": "您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。",
|
||||||
"eventUpdateTotpBodyHtml": "<p>您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。</p>"
|
"eventUpdateTotpBodyHtml": "<p>您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。</p>"
|
||||||
}
|
}
|
||||||
} as const;
|
};
|
||||||
/* spell-checker: enable */
|
/* spell-checker: enable */
|
@ -2,10 +2,10 @@
|
|||||||
//PLEASE DO NOT EDIT MANUALLY
|
//PLEASE DO NOT EDIT MANUALLY
|
||||||
|
|
||||||
/* spell-checker: disable */
|
/* spell-checker: disable */
|
||||||
export const messages= {
|
export const kcMessages= {
|
||||||
"ca": {
|
"ca": {
|
||||||
"doLogIn": "Inicia sessió",
|
"doLogIn": "Inicia sessió",
|
||||||
"doRegister": "Registra''t",
|
"doRegister": "Registra't",
|
||||||
"doCancel": "Cancel·lar",
|
"doCancel": "Cancel·lar",
|
||||||
"doSubmit": "Envia",
|
"doSubmit": "Envia",
|
||||||
"doYes": "Sí",
|
"doYes": "Sí",
|
||||||
@ -20,7 +20,7 @@ export const messages= {
|
|||||||
"kerberosNotConfiguredTitle": "Kerberos no configurat",
|
"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à.",
|
"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.",
|
"kerberosNotSetUp": "Kerberos no està configurat. No pots identificar-te.",
|
||||||
"registerWithTitle": "Registra''t amb {0}",
|
"registerWithTitle": "Registra't amb {0}",
|
||||||
"registerWithTitleHtml": "{0}",
|
"registerWithTitleHtml": "{0}",
|
||||||
"loginTitle": "Inicia sessió a {0}",
|
"loginTitle": "Inicia sessió a {0}",
|
||||||
"loginTitleHtml": "{0}",
|
"loginTitleHtml": "{0}",
|
||||||
@ -28,18 +28,18 @@ export const messages= {
|
|||||||
"impersonateTitleHtml": "<strong>{0}</strong> Personifica Usuari",
|
"impersonateTitleHtml": "<strong>{0}</strong> Personifica Usuari",
|
||||||
"realmChoice": "Domini",
|
"realmChoice": "Domini",
|
||||||
"unknownUser": "Usuari desconegut",
|
"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",
|
"loginProfileTitle": "Actualitza la informació del teu compte",
|
||||||
"loginTimeout": "Has trigat massa a identificar-te. Inicia de nou la identificació.",
|
"loginTimeout": "Has trigat massa a identificar-te. Inicia de nou la identificació.",
|
||||||
"oauthGrantTitle": "Concessió OAuth",
|
"oauthGrantTitle": "Concessió OAuth",
|
||||||
"oauthGrantTitleHtml": "{0}",
|
"oauthGrantTitleHtml": "{0}",
|
||||||
"errorTitle": "Ho sentim...",
|
"errorTitle": "Ho sentim...",
|
||||||
"errorTitleHtml": "Ho <strong>sentim</strong>...",
|
"errorTitleHtml": "Ho <strong>sentim</strong>...",
|
||||||
"emailVerifyTitle": "Verificació de l''email",
|
"emailVerifyTitle": "Verificació de l'email",
|
||||||
"emailForgotTitle": "Has oblidat la teva contrasenya?",
|
"emailForgotTitle": "Has oblidat la teva contrasenya?",
|
||||||
"updatePasswordTitle": "Modificació de contrasenya",
|
"updatePasswordTitle": "Modificació de contrasenya",
|
||||||
"codeSuccessTitle": "Codi d''èxit",
|
"codeSuccessTitle": "Codi d'èxit",
|
||||||
"codeErrorTitle": "Codi d''error: {0}",
|
"codeErrorTitle": "Codi d'error: {0}",
|
||||||
"termsTitle": "Termes i Condicions",
|
"termsTitle": "Termes i Condicions",
|
||||||
"termsTitleHtml": "Termes i Condicions",
|
"termsTitleHtml": "Termes i Condicions",
|
||||||
"termsText": "<p>Termes i condicions a definir</p>",
|
"termsText": "<p>Termes i condicions a definir</p>",
|
||||||
@ -60,7 +60,7 @@ export const messages= {
|
|||||||
"passwordNew": "Nova contrasenya",
|
"passwordNew": "Nova contrasenya",
|
||||||
"passwordNewConfirm": "Confirma la nova contrasenya",
|
"passwordNewConfirm": "Confirma la nova contrasenya",
|
||||||
"rememberMe": "Seguir connectat",
|
"rememberMe": "Seguir connectat",
|
||||||
"authenticatorCode": "Codi d''identificació",
|
"authenticatorCode": "Codi d'identificació",
|
||||||
"address": "Adreça",
|
"address": "Adreça",
|
||||||
"street": "Carrer",
|
"street": "Carrer",
|
||||||
"locality": "Ciutat o Municipi",
|
"locality": "Ciutat o Municipi",
|
||||||
@ -69,17 +69,17 @@ export const messages= {
|
|||||||
"country": "País",
|
"country": "País",
|
||||||
"emailVerified": "Email verificat",
|
"emailVerified": "Email verificat",
|
||||||
"gssDelegationCredential": "GSS Delegation Credential",
|
"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.",
|
"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.",
|
"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ó",
|
"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",
|
"loginOtpOneTime": "Codi d'un sol ús",
|
||||||
"oauthGrantRequest": "Vols permetre aquests privilegis d''accés?",
|
"oauthGrantRequest": "Vols permetre aquests privilegis d'accés?",
|
||||||
"inResource": "a",
|
"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?",
|
"emailVerifyInstruction2": "No has rebut un codi de verificació al teu email?",
|
||||||
"emailVerifyInstruction3": "per reenviar l''email.",
|
"emailVerifyInstruction3": "per reenviar l'email.",
|
||||||
"backToLogin": "« Torna a la identificació",
|
"backToLogin": "« 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ó:",
|
"copyCodeInstruction": "Si us plau, copia i enganxa aquest codi a la teva aplicació:",
|
||||||
"personalInfo": "Informació personal:",
|
"personalInfo": "Informació personal:",
|
||||||
"role_admin": "Admin",
|
"role_admin": "Admin",
|
||||||
@ -91,11 +91,11 @@ export const messages= {
|
|||||||
"role_view-applications": "Veure aplicacions",
|
"role_view-applications": "Veure aplicacions",
|
||||||
"role_view-clients": "Veure clients",
|
"role_view-clients": "Veure clients",
|
||||||
"role_view-events": "Veure events",
|
"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-realm": "Gestionar domini",
|
||||||
"role_manage-users": "Gestionar usuaris",
|
"role_manage-users": "Gestionar usuaris",
|
||||||
"role_manage-applications": "Gestionar aplicacions",
|
"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-clients": "Gestionar clients",
|
||||||
"role_manage-events": "Gestionar events",
|
"role_manage-events": "Gestionar events",
|
||||||
"role_view-profile": "Veure perfil",
|
"role_view-profile": "Veure perfil",
|
||||||
@ -103,79 +103,79 @@ export const messages= {
|
|||||||
"role_read-token": "Llegir token",
|
"role_read-token": "Llegir token",
|
||||||
"role_offline-access": "Accés sense connexió",
|
"role_offline-access": "Accés sense connexió",
|
||||||
"client_account": "Compte",
|
"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_realm-management": "Gestió del domini",
|
||||||
"client_broker": "Broker",
|
"client_broker": "Broker",
|
||||||
"invalidUserMessage": "Usuari o contrasenya incorrectes.",
|
"invalidUserMessage": "Usuari o contrasenya incorrectes.",
|
||||||
"invalidEmailMessage": "Email no vàlid",
|
"invalidEmailMessage": "Email no vàlid",
|
||||||
"accountDisabledMessage": "El compte està desactivat, contacta amb l''administrador.",
|
"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.",
|
"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.",
|
"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.",
|
"missingFirstNameMessage": "Si us plau indica el teu nom.",
|
||||||
"missingLastNameMessage": "Si us plau indica els teus cognoms.",
|
"missingLastNameMessage": "Si us plau indica els teus cognoms.",
|
||||||
"missingEmailMessage": "Si us plau indica el teu email.",
|
"missingEmailMessage": "Si us plau indica el teu email.",
|
||||||
"missingUsernameMessage": "Si us plau indica el teu usuari.",
|
"missingUsernameMessage": "Si us plau indica el teu usuari.",
|
||||||
"missingPasswordMessage": "Si us plau indica la teva contrasenya.",
|
"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.",
|
"notMatchPasswordMessage": "Les contrasenyes no coincideixen.",
|
||||||
"invalidPasswordExistingMessage": "La contrasenya actual no és correcta.",
|
"invalidPasswordExistingMessage": "La contrasenya actual no és correcta.",
|
||||||
"invalidPasswordConfirmMessage": "La confirmació de contrasenya no coincideix.",
|
"invalidPasswordConfirmMessage": "La confirmació de contrasenya no coincideix.",
|
||||||
"invalidTotpMessage": "El codi d''autenticació no és vàlid.",
|
"invalidTotpMessage": "El codi d'autenticació no és vàlid.",
|
||||||
"usernameExistsMessage": "El nom d''usuari ja existeix",
|
"usernameExistsMessage": "El nom d'usuari ja existeix",
|
||||||
"emailExistsMessage": "L''email 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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"updatePasswordMessage": "Has de canviar la contrasenya per activar el teu compte.",
|
||||||
"verifyEmailMessage": "Has de verificar el teu email 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",
|
"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.",
|
"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.",
|
"accountUpdatedMessage": "El teu compte s'ha actualitzat.",
|
||||||
"accountPasswordUpdatedMessage": "La contrasenya s''ha actualitzat.",
|
"accountPasswordUpdatedMessage": "La contrasenya s'ha actualitzat.",
|
||||||
"noAccessMessage": "Sense accés",
|
"noAccessMessage": "Sense accés",
|
||||||
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mínima {0}.",
|
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mínima {0}.",
|
||||||
"invalidPasswordMinDigitsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters numèrics.",
|
"invalidPasswordMinDigitsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters numèrics.",
|
||||||
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
|
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minúscules.",
|
||||||
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
|
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majúscules.",
|
||||||
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
|
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} caràcters especials.",
|
||||||
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d''usuari.",
|
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
|
||||||
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l''expressió regular.",
|
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressió regular.",
|
||||||
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes.",
|
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les últimes {0} contrasenyes.",
|
||||||
"failedToProcessResponseMessage": "Fallada en processar la resposta",
|
"failedToProcessResponseMessage": "Fallada en processar la resposta",
|
||||||
"httpsRequiredMessage": "HTTPS obligatori",
|
"httpsRequiredMessage": "HTTPS obligatori",
|
||||||
"realmNotEnabledMessage": "El domini no està activat",
|
"realmNotEnabledMessage": "El domini no està activat",
|
||||||
"invalidRequestMessage": "Petició incorrecta",
|
"invalidRequestMessage": "Petició incorrecta",
|
||||||
"failedLogout": "Ha fallat la desconnexió.",
|
"failedLogout": "Ha fallat la desconnexió.",
|
||||||
"unknownLoginRequesterMessage": "Sol·licitant d''identificació desconegut",
|
"unknownLoginRequesterMessage": "Sol·licitant d'identificació desconegut",
|
||||||
"loginRequesterNotEnabledMessage": "El sol·licitant d''inici de sessió està desactivat",
|
"loginRequesterNotEnabledMessage": "El sol·licitant d'inici de sessió està desactivat",
|
||||||
"bearerOnlyMessage": "Les aplicacions Bearer-only no poden iniciar sessió des del navegador.",
|
"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.",
|
"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",
|
"unsupportedNameIdFormatMessage": "NameIDFormat no suportat",
|
||||||
"invalidRequesterMessage": "Sol·licitant no vàlid",
|
"invalidRequesterMessage": "Sol·licitant no vàlid",
|
||||||
"registrationNotAllowedMessage": "El registre no està permès",
|
"registrationNotAllowedMessage": "El registre no està permès",
|
||||||
"resetCredentialNotAllowedMessage": "El reinici de les credencials no està permès",
|
"resetCredentialNotAllowedMessage": "El reinici de les credencials no està permès",
|
||||||
"permissionNotApprovedMessage": "Permís no aprovat.",
|
"permissionNotApprovedMessage": "Permís no aprovat.",
|
||||||
"noRelayStateInResponseMessage": "Sense estat de retransmissió en la resposta del proveïdor d''identitat.",
|
"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.",
|
"identityProviderAlreadyLinkedMessage": "La identitat retornada pel proveïdor d'identitat ja està associada a un altre usuari.",
|
||||||
"insufficientPermissionMessage": "Permisos insuficients per enllaçar identitats.",
|
"insufficientPermissionMessage": "Permisos insuficients per enllaçar identitats.",
|
||||||
"couldNotProceedWithAuthenticationRequestMessage": "No s''ha pogut continuar amb la petició d''autenticació al proveïdor d''identitat.",
|
"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.",
|
"couldNotObtainTokenMessage": "No s'ha pogut obtenir el codi del proveïdor d'identitat.",
|
||||||
"unexpectedErrorRetrievingTokenMessage": "Error inesperat obtenint el token 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.",
|
"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.",
|
"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.",
|
"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.",
|
"unexpectedErrorHandlingRequestMessage": "Error inesperat durant la petició d'identificació al proveïdor d'identitat.",
|
||||||
"invalidAccessCodeMessage": "Codi d''accés no vàlid.",
|
"invalidAccessCodeMessage": "Codi d'accés no vàlid.",
|
||||||
"sessionNotActiveMessage": "La sessió no està activa",
|
"sessionNotActiveMessage": "La sessió no està activa",
|
||||||
"invalidCodeMessage": "Hi ha hagut un error, si us plau identifica''t de nou des de la teva aplicació.",
|
"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.",
|
"identityProviderUnexpectedErrorMessage": "Error no esperat intentant autenticar en el proveïdor d'identitat.",
|
||||||
"identityProviderNotFoundMessage": "No s''ha trobat cap proveïdor d''identitat.",
|
"identityProviderNotFoundMessage": "No s'ha trobat cap proveïdor d'identitat.",
|
||||||
"realmSupportsNoCredentialsMessage": "El domini no suporta cap tipus de credencials.",
|
"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.",
|
"emailVerifiedMessage": "El teu email ha estat verificat.",
|
||||||
"backToApplication": "« Torna a l''aplicació",
|
"backToApplication": "« Torna a l'aplicació",
|
||||||
"missingParameterMessage": "Paràmetres que falten: {0}",
|
"missingParameterMessage": "Paràmetres que falten: {0}",
|
||||||
"clientNotFoundMessage": "Client no trobat",
|
"clientNotFoundMessage": "Client no trobat",
|
||||||
"invalidParameterMessage": "Paràmetre no vàlid: {0}",
|
"invalidParameterMessage": "Paràmetre no vàlid: {0}",
|
||||||
@ -401,7 +401,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "Klient byl zneplatněn.",
|
"clientDisabledMessage": "Klient byl zneplatněn.",
|
||||||
"invalidParameterMessage": "Neplatný parametr : {0}",
|
"invalidParameterMessage": "Neplatný parametr : {0}",
|
||||||
"alreadyLoggedIn": "Jste již přihlášeni.",
|
"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á.",
|
"brokerLinkingSessionExpired": "Požadované propojení účtu brokerů, ale aktuální relace již není platná.",
|
||||||
"proceedWithAction": "» Klikněte zde pro pokračování",
|
"proceedWithAction": "» Klikněte zde pro pokračování",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Konfigurovat OTP",
|
"requiredAction.CONFIGURE_TOTP": "Konfigurovat OTP",
|
||||||
@ -631,7 +631,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "Client deaktiviert.",
|
"clientDisabledMessage": "Client deaktiviert.",
|
||||||
"invalidParameterMessage": "Ungültiger Parameter: {0}",
|
"invalidParameterMessage": "Ungültiger Parameter: {0}",
|
||||||
"alreadyLoggedIn": "Sie sind bereits angemeldet.",
|
"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.",
|
"brokerLinkingSessionExpired": "Broker Account Linking angefordert; Ihre Session ist allerdings nicht mehr gültig.",
|
||||||
"proceedWithAction": "» Klicken Sie hier um fortzufahren",
|
"proceedWithAction": "» Klicken Sie hier um fortzufahren",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Mehrfachauthentifizierung konfigurieren",
|
"requiredAction.CONFIGURE_TOTP": "Mehrfachauthentifizierung konfigurieren",
|
||||||
@ -750,11 +750,11 @@ export const messages= {
|
|||||||
"oauthGrantRequest": "Do you grant these access privileges?",
|
"oauthGrantRequest": "Do you grant these access privileges?",
|
||||||
"inResource": "in",
|
"inResource": "in",
|
||||||
"emailVerifyInstruction1": "An email with instructions to verify your email address has been sent to you.",
|
"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.",
|
"emailVerifyInstruction3": "to re-send the email.",
|
||||||
"emailLinkIdpTitle": "Link {0}",
|
"emailLinkIdpTitle": "Link {0}",
|
||||||
"emailLinkIdp1": "An email with instructions to link {0} account {1} with your {2} account has been sent to you.",
|
"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.",
|
"emailLinkIdp3": "to re-send the email.",
|
||||||
"emailLinkIdp4": "If you already verified the email in different browser",
|
"emailLinkIdp4": "If you already verified the email in different browser",
|
||||||
"emailLinkIdp5": "to continue.",
|
"emailLinkIdp5": "to continue.",
|
||||||
@ -811,10 +811,10 @@ export const messages= {
|
|||||||
"missingPasswordMessage": "Please specify password.",
|
"missingPasswordMessage": "Please specify password.",
|
||||||
"missingTotpMessage": "Please specify authenticator code.",
|
"missingTotpMessage": "Please specify authenticator code.",
|
||||||
"missingTotpDeviceNameMessage": "Please specify device name.",
|
"missingTotpDeviceNameMessage": "Please specify device name.",
|
||||||
"notMatchPasswordMessage": "Passwords don''t match.",
|
"notMatchPasswordMessage": "Passwords don't match.",
|
||||||
"invalidPasswordExistingMessage": "Invalid existing password.",
|
"invalidPasswordExistingMessage": "Invalid existing password.",
|
||||||
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
|
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
|
||||||
"invalidPasswordConfirmMessage": "Password confirmation doesn''t match.",
|
"invalidPasswordConfirmMessage": "Password confirmation doesn't match.",
|
||||||
"invalidTotpMessage": "Invalid authenticator code.",
|
"invalidTotpMessage": "Invalid authenticator code.",
|
||||||
"usernameExistsMessage": "Username already exists.",
|
"usernameExistsMessage": "Username already exists.",
|
||||||
"emailExistsMessage": "Email already exists.",
|
"emailExistsMessage": "Email already exists.",
|
||||||
@ -848,7 +848,7 @@ export const messages= {
|
|||||||
"invalidPasswordNotUsernameMessage": "Invalid password: must not be equal to the username.",
|
"invalidPasswordNotUsernameMessage": "Invalid password: must not be equal to the username.",
|
||||||
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
|
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
|
||||||
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
|
"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",
|
"failedToProcessResponseMessage": "Failed to process response",
|
||||||
"httpsRequiredMessage": "HTTPS required",
|
"httpsRequiredMessage": "HTTPS required",
|
||||||
"realmNotEnabledMessage": "Realm not enabled",
|
"realmNotEnabledMessage": "Realm not enabled",
|
||||||
@ -914,7 +914,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "Client disabled.",
|
"clientDisabledMessage": "Client disabled.",
|
||||||
"invalidParameterMessage": "Invalid parameter: {0}",
|
"invalidParameterMessage": "Invalid parameter: {0}",
|
||||||
"alreadyLoggedIn": "You are already logged in.",
|
"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.",
|
"brokerLinkingSessionExpired": "Requested broker account linking, but current session is no longer valid.",
|
||||||
"proceedWithAction": "» Click here to proceed",
|
"proceedWithAction": "» Click here to proceed",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Configure OTP",
|
"requiredAction.CONFIGURE_TOTP": "Configure OTP",
|
||||||
@ -1162,9 +1162,9 @@ export const messages= {
|
|||||||
"doImpersonate": "Impersonate",
|
"doImpersonate": "Impersonate",
|
||||||
"kerberosNotConfigured": "Kerberos non configuré",
|
"kerberosNotConfigured": "Kerberos non configuré",
|
||||||
"kerberosNotConfiguredTitle": "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.",
|
"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.",
|
"kerberosNotSetUp": "Kerberos n'est pas configuré. Connexion impossible.",
|
||||||
"registerTitle": "S''enregistrer",
|
"registerTitle": "S'enregistrer",
|
||||||
"registerWithTitle": "Enregistrement avec {0}",
|
"registerWithTitle": "Enregistrement avec {0}",
|
||||||
"registerWithTitleHtml": "{0}",
|
"registerWithTitleHtml": "{0}",
|
||||||
"loginTitle": "Se connecter à {0}",
|
"loginTitle": "Se connecter à {0}",
|
||||||
@ -1173,7 +1173,7 @@ export const messages= {
|
|||||||
"impersonateTitleHtml": "<strong>{0}</strong> utilisateur impersonate",
|
"impersonateTitleHtml": "<strong>{0}</strong> utilisateur impersonate",
|
||||||
"realmChoice": "Domaine",
|
"realmChoice": "Domaine",
|
||||||
"unknownUser": "Utilisateur inconnu",
|
"unknownUser": "Utilisateur inconnu",
|
||||||
"loginTotpTitle": "Configuration de l''authentification par mobile",
|
"loginTotpTitle": "Configuration de l'authentification par mobile",
|
||||||
"loginProfileTitle": "Mise à jour du compte",
|
"loginProfileTitle": "Mise à jour du compte",
|
||||||
"loginTimeout": "Le temps imparti pour la connexion est écoulé. Le processus de connexion redémarre depuis le début.",
|
"loginTimeout": "Le temps imparti pour la connexion est écoulé. Le processus de connexion redémarre depuis le début.",
|
||||||
"oauthGrantTitle": "OAuth Grant",
|
"oauthGrantTitle": "OAuth Grant",
|
||||||
@ -1184,8 +1184,8 @@ export const messages= {
|
|||||||
"emailForgotTitle": "Mot de passe oublié ?",
|
"emailForgotTitle": "Mot de passe oublié ?",
|
||||||
"updatePasswordTitle": "Mise à jour du mot de passe",
|
"updatePasswordTitle": "Mise à jour du mot de passe",
|
||||||
"codeSuccessTitle": "Code succès",
|
"codeSuccessTitle": "Code succès",
|
||||||
"codeErrorTitle": "Code d''erreur : {0}",
|
"codeErrorTitle": "Code d'erreur : {0}",
|
||||||
"displayUnsupported": "Type d''affichage demandé non supporté",
|
"displayUnsupported": "Type d'affichage demandé non supporté",
|
||||||
"browserRequired": "Navigateur requis pour se connecter",
|
"browserRequired": "Navigateur requis pour se connecter",
|
||||||
"browserContinue": "Navigateur requis pour continuer la connexion",
|
"browserContinue": "Navigateur requis pour continuer la connexion",
|
||||||
"browserContinuePrompt": "Ouvrir le navigateur et continuer la connexion? [y/n]:",
|
"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>",
|
"termsText": "<p>Termes et conditions à définir</p>",
|
||||||
"termsPlainText": "Termes et conditions à définir",
|
"termsPlainText": "Termes et conditions à définir",
|
||||||
"recaptchaFailed": "Re-captcha invalide",
|
"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é.",
|
"consentDenied": "Consentement refusé.",
|
||||||
"noAccount": "Nouvel utilisateur ?",
|
"noAccount": "Nouvel utilisateur ?",
|
||||||
"username": "Nom d''utilisateur",
|
"username": "Nom d'utilisateur",
|
||||||
"usernameOrEmail": "Nom d''utilisateur ou courriel",
|
"usernameOrEmail": "Nom d'utilisateur ou courriel",
|
||||||
"firstName": "Prénom",
|
"firstName": "Prénom",
|
||||||
"givenName": "Prénom",
|
"givenName": "Prénom",
|
||||||
"fullName": "Nom complet",
|
"fullName": "Nom complet",
|
||||||
@ -1222,10 +1222,10 @@ export const messages= {
|
|||||||
"gssDelegationCredential": "Accréditation de délégation GSS",
|
"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",
|
"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.",
|
"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.",
|
"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.",
|
"loginTotpStep3": "Entrez le code à usage unique fourni par l'application et cliquez sur Sauvegarder pour terminer.",
|
||||||
"loginTotpManualStep2": "Ouvrez l''application et saisissez la clé",
|
"loginTotpManualStep2": "Ouvrez l'application et saisissez la clé",
|
||||||
"loginTotpManualStep3": "Utilisez la configuration de valeur suivante si l''application permet son édition",
|
"loginTotpManualStep3": "Utilisez la configuration de valeur suivante si l'application permet son édition",
|
||||||
"loginTotpUnableToScan": "Impossible de scanner?",
|
"loginTotpUnableToScan": "Impossible de scanner?",
|
||||||
"loginTotpScanBarcode": "Scanner le code barre ?",
|
"loginTotpScanBarcode": "Scanner le code barre ?",
|
||||||
"loginOtpOneTime": "Code à usage unique",
|
"loginOtpOneTime": "Code à usage unique",
|
||||||
@ -1236,23 +1236,23 @@ export const messages= {
|
|||||||
"loginTotpCounter": "Compteur",
|
"loginTotpCounter": "Compteur",
|
||||||
"loginTotp.totp": "Basé sur le temps",
|
"loginTotp.totp": "Basé sur le temps",
|
||||||
"loginTotp.hotp": "Basé sur les compteurs",
|
"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",
|
"inResource": "dans",
|
||||||
"emailVerifyInstruction1": "Un courriel avec des instructions à suivre vous a été envoyé.",
|
"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.",
|
"emailVerifyInstruction3": "pour renvoyer le courriel.",
|
||||||
"emailLinkIdpTitle": "Association avec {0}",
|
"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é.",
|
"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.",
|
"emailLinkIdp3": "pour renvoyer le courriel.",
|
||||||
"emailLinkIdp4": "Si vous avez déjà vérifié votre courriel dans un autre navigateur",
|
"emailLinkIdp4": "Si vous avez déjà vérifié votre courriel dans un autre navigateur",
|
||||||
"emailLinkIdp5": "pour continuer.",
|
"emailLinkIdp5": "pour continuer.",
|
||||||
"backToLogin": "« Retour à la connexion",
|
"backToLogin": "« 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 :",
|
"copyCodeInstruction": "Copiez le code et recopiez le dans votre application :",
|
||||||
"pageExpiredTitle": "La page a expiré",
|
"pageExpiredTitle": "La page a expiré",
|
||||||
"pageExpiredMsg1": "Pour recommencer le processus d''authentification",
|
"pageExpiredMsg1": "Pour recommencer le processus d'authentification",
|
||||||
"pageExpiredMsg2": "Pour continuer le processus d''authentification",
|
"pageExpiredMsg2": "Pour continuer le processus d'authentification",
|
||||||
"personalInfo": "Information personnelle :",
|
"personalInfo": "Information personnelle :",
|
||||||
"role_admin": "Administrateur",
|
"role_admin": "Administrateur",
|
||||||
"role_realm-admin": "Administrateur du domaine",
|
"role_realm-admin": "Administrateur du domaine",
|
||||||
@ -1263,24 +1263,24 @@ export const messages= {
|
|||||||
"role_view-applications": "Voir les applications",
|
"role_view-applications": "Voir les applications",
|
||||||
"role_view-clients": "Voir les clients",
|
"role_view-clients": "Voir les clients",
|
||||||
"role_view-events": "Voir les événements",
|
"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-realm": "Gérer le domaine",
|
||||||
"role_manage-users": "Gérer les utilisateurs",
|
"role_manage-users": "Gérer les utilisateurs",
|
||||||
"role_manage-applications": "Gérer les applications",
|
"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-clients": "Gérer les clients",
|
||||||
"role_manage-events": "Gérer les événements",
|
"role_manage-events": "Gérer les événements",
|
||||||
"role_view-profile": "Voir le profil",
|
"role_view-profile": "Voir le profil",
|
||||||
"role_manage-account": "Gérer le compte",
|
"role_manage-account": "Gérer le compte",
|
||||||
"role_manage-account-links": "Gérer les liens de 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",
|
"role_offline-access": "Accès hors-ligne",
|
||||||
"client_account": "Compte",
|
"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_admin-cli": "Admin CLI",
|
||||||
"client_realm-management": "Gestion du domaine",
|
"client_realm-management": "Gestion du domaine",
|
||||||
"client_broker": "Broker",
|
"client_broker": "Broker",
|
||||||
"invalidUserMessage": "Nom d''utilisateur ou mot de passe invalide.",
|
"invalidUserMessage": "Nom d'utilisateur ou mot de passe invalide.",
|
||||||
"invalidEmailMessage": "Courriel invalide.",
|
"invalidEmailMessage": "Courriel invalide.",
|
||||||
"accountDisabledMessage": "Compte désactivé, contactez votre administrateur.",
|
"accountDisabledMessage": "Compte désactivé, contactez votre administrateur.",
|
||||||
"accountTemporarilyDisabledMessage": "Ce compte est temporairement désactivé, contactez votre administrateur ou bien réessayez plus tard.",
|
"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.",
|
"missingFirstNameMessage": "Veuillez entrer votre prénom.",
|
||||||
"missingLastNameMessage": "Veuillez entrer votre nom.",
|
"missingLastNameMessage": "Veuillez entrer votre nom.",
|
||||||
"missingEmailMessage": "Veuillez entrer votre courriel.",
|
"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.",
|
"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.",
|
"notMatchPasswordMessage": "Les mots de passe ne sont pas identiques.",
|
||||||
"invalidPasswordExistingMessage": "Mot de passe existant invalide.",
|
"invalidPasswordExistingMessage": "Mot de passe existant invalide.",
|
||||||
"invalidPasswordBlacklistedMessage": "Mot de passe invalide : ce mot de passe est blacklisté.",
|
"invalidPasswordBlacklistedMessage": "Mot de passe invalide : ce mot de passe est blacklisté.",
|
||||||
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
|
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
|
||||||
"invalidTotpMessage": "Le code d''authentification est invalide.",
|
"invalidTotpMessage": "Le code d'authentification est invalide.",
|
||||||
"usernameExistsMessage": "Le nom d''utilisateur existe déjà.",
|
"usernameExistsMessage": "Le nom d'utilisateur existe déjà.",
|
||||||
"emailExistsMessage": "Le courriel 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.",
|
"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à",
|
"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}",
|
"federatedIdentityConfirmReauthenticateMessage": "Identifiez vous afin de lier votre compte avec {0}",
|
||||||
"confirmLinkIdpReviewProfile": "Vérifiez vos informations de profil",
|
"confirmLinkIdpReviewProfile": "Vérifiez vos informations de profil",
|
||||||
"confirmLinkIdpContinue": "Souhaitez-vous lier {0} à votre compte existant",
|
"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.",
|
"updateProfileMessage": "Vous devez mettre à jour votre profil pour activer votre compte.",
|
||||||
"updatePasswordMessage": "Vous devez changer votre mot de passe pour activer votre compte.",
|
"updatePasswordMessage": "Vous devez changer votre mot de passe pour activer votre compte.",
|
||||||
"resetPasswordMessage": "Vous devez changer votre mot de passe.",
|
"resetPasswordMessage": "Vous devez changer votre mot de passe.",
|
||||||
"verifyEmailMessage": "Vous devez vérifier votre courriel pour activer votre compte.",
|
"verifyEmailMessage": "Vous devez vérifier votre courriel pour activer votre compte.",
|
||||||
"linkIdpMessage": "Vous devez vérifier votre courriel pour lier votre compte avec {0}.",
|
"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.",
|
"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.",
|
"accountUpdatedMessage": "Votre compte a été mis à jour.",
|
||||||
"accountPasswordUpdatedMessage": "Votre mot de passe a été mis à jour.",
|
"accountPasswordUpdatedMessage": "Votre mot de passe a été mis à jour.",
|
||||||
"noAccessMessage": "Aucun accès",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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",
|
"failedToProcessResponseMessage": "Erreur lors du traitement de la réponse",
|
||||||
"httpsRequiredMessage": "Le protocole HTTPS est requis",
|
"httpsRequiredMessage": "Le protocole HTTPS est requis",
|
||||||
"realmNotEnabledMessage": "Le domaine n''est pas activé",
|
"realmNotEnabledMessage": "Le domaine n'est pas activé",
|
||||||
"invalidRequestMessage": "Requête invalide",
|
"invalidRequestMessage": "Requête invalide",
|
||||||
"failedLogout": "La déconnexion a échouée",
|
"failedLogout": "La déconnexion a échouée",
|
||||||
"unknownLoginRequesterMessage": "Compte inconnu du demandeur",
|
"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.",
|
"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.",
|
"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.",
|
"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",
|
"invalidRedirectUriMessage": "L'URI de redirection est invalide",
|
||||||
"unsupportedNameIdFormatMessage": "NameIDFormat non supporté",
|
"unsupportedNameIdFormatMessage": "NameIDFormat non supporté",
|
||||||
"invalidRequesterMessage": "Demandeur invalide",
|
"invalidRequesterMessage": "Demandeur invalide",
|
||||||
"registrationNotAllowedMessage": "L''enregistrement n''est pas autorisé",
|
"registrationNotAllowedMessage": "L'enregistrement n'est pas autorisé",
|
||||||
"resetCredentialNotAllowedMessage": "La remise à zéro n''est pas autorisée",
|
"resetCredentialNotAllowedMessage": "La remise à zéro n'est pas autorisée",
|
||||||
"permissionNotApprovedMessage": "La permission n''est pas approuvée.",
|
"permissionNotApprovedMessage": "La permission n'est pas approuvée.",
|
||||||
"noRelayStateInResponseMessage": "Aucun état de relais dans la réponse du fournisseur d''identité.",
|
"noRelayStateInResponseMessage": "Aucun état de relais dans la réponse du fournisseur d'identité.",
|
||||||
"insufficientPermissionMessage": "Permissions insuffisantes pour lier les identités.",
|
"insufficientPermissionMessage": "Permissions insuffisantes pour lier les identités.",
|
||||||
"couldNotProceedWithAuthenticationRequestMessage": "Impossible de continuer avec la requête d''authentification vers le fournisseur d''identité.",
|
"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é.",
|
"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é.",
|
"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é.",
|
"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é.",
|
"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é.",
|
"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é.",
|
"unexpectedErrorHandlingRequestMessage": "Erreur inattendue lors du traitement de la requête vers le fournisseur d'identité.",
|
||||||
"invalidAccessCodeMessage": "Code d''accès invalide.",
|
"invalidAccessCodeMessage": "Code d'accès invalide.",
|
||||||
"sessionNotActiveMessage": "La session n''est pas active.",
|
"sessionNotActiveMessage": "La session n'est pas active.",
|
||||||
"invalidCodeMessage": "Une erreur est survenue, veuillez vous reconnecter à votre application.",
|
"invalidCodeMessage": "Une erreur est survenue, veuillez vous reconnecter à votre application.",
|
||||||
"identityProviderUnexpectedErrorMessage": "Erreur inattendue lors de l''authentification avec fournisseur d''identité.",
|
"identityProviderUnexpectedErrorMessage": "Erreur inattendue lors de l'authentification avec fournisseur d'identité.",
|
||||||
"identityProviderNotFoundMessage": "Impossible de trouver le fournisseur d''identité avec cet identifiant.",
|
"identityProviderNotFoundMessage": "Impossible de trouver le fournisseur d'identité avec cet identifiant.",
|
||||||
"identityProviderLinkSuccess": "Votre compte a été correctement lié avec {0} compte {1} .",
|
"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.",
|
"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.",
|
"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.",
|
"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é.",
|
"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 ?",
|
"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.",
|
"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.",
|
"confirmAccountLinking": "Confirmez la liaison du compte {0} du fournisseur d'entité {1} avec votre compte.",
|
||||||
"confirmEmailAddressVerification": "Confirmez la validité de l''adresse courriel {0}.",
|
"confirmEmailAddressVerification": "Confirmez la validité de l'adresse courriel {0}.",
|
||||||
"confirmExecutionOfActions": "Suivez les instructions suivantes",
|
"confirmExecutionOfActions": "Suivez les instructions suivantes",
|
||||||
"backToApplication": "« Revenir à l''application",
|
"backToApplication": "« Revenir à l'application",
|
||||||
"missingParameterMessage": "Paramètres manquants : {0}",
|
"missingParameterMessage": "Paramètres manquants : {0}",
|
||||||
"clientNotFoundMessage": "Client inconnu.",
|
"clientNotFoundMessage": "Client inconnu.",
|
||||||
"clientDisabledMessage": "Client désactivé.",
|
"clientDisabledMessage": "Client désactivé.",
|
||||||
"invalidParameterMessage": "Paramètre invalide : {0}",
|
"invalidParameterMessage": "Paramètre invalide : {0}",
|
||||||
"alreadyLoggedIn": "Vous êtes déjà connecté.",
|
"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": "» Cliquez ici",
|
"proceedWithAction": "» Cliquez ici",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Configurer OTP",
|
"requiredAction.CONFIGURE_TOTP": "Configurer OTP",
|
||||||
"requiredAction.terms_and_conditions": "Termes et conditions",
|
"requiredAction.terms_and_conditions": "Termes et conditions",
|
||||||
@ -1385,7 +1385,7 @@ export const messages= {
|
|||||||
"clientCertificate": "X509 certificat client:",
|
"clientCertificate": "X509 certificat client:",
|
||||||
"noCertificate": "[Pas de certificat]",
|
"noCertificate": "[Pas de certificat]",
|
||||||
"pageNotFound": "Page non trouvée",
|
"pageNotFound": "Page non trouvée",
|
||||||
"internalServerError": "Une erreur interne du serveur s''est produite"
|
"internalServerError": "Une erreur interne du serveur s'est produite"
|
||||||
},
|
},
|
||||||
"it": {
|
"it": {
|
||||||
"doLogIn": "Accedi",
|
"doLogIn": "Accedi",
|
||||||
@ -1406,8 +1406,8 @@ export const messages= {
|
|||||||
"doTryAnotherWay": "Prova in un altro modo",
|
"doTryAnotherWay": "Prova in un altro modo",
|
||||||
"kerberosNotConfigured": "Kerberos non configurato",
|
"kerberosNotConfigured": "Kerberos non configurato",
|
||||||
"kerberosNotConfiguredTitle": "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.",
|
"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.",
|
"kerberosNotSetUp": "Kerberos non è configurato. Non puoi effettuare l'accesso.",
|
||||||
"registerTitle": "Registrati",
|
"registerTitle": "Registrati",
|
||||||
"loginTitle": "Accedi a {0}",
|
"loginTitle": "Accedi a {0}",
|
||||||
"loginTitleHtml": "{0}",
|
"loginTitleHtml": "{0}",
|
||||||
@ -1422,7 +1422,7 @@ export const messages= {
|
|||||||
"oauthGrantTitleHtml": "{0}",
|
"oauthGrantTitleHtml": "{0}",
|
||||||
"errorTitle": "Siamo spiacenti…",
|
"errorTitle": "Siamo spiacenti…",
|
||||||
"errorTitleHtml": "Siamo <strong>spiacenti</strong>...",
|
"errorTitleHtml": "Siamo <strong>spiacenti</strong>...",
|
||||||
"emailVerifyTitle": "Verifica l''email",
|
"emailVerifyTitle": "Verifica l'email",
|
||||||
"emailForgotTitle": "Password dimenticata?",
|
"emailForgotTitle": "Password dimenticata?",
|
||||||
"updatePasswordTitle": "Aggiorna password",
|
"updatePasswordTitle": "Aggiorna password",
|
||||||
"codeSuccessTitle": "Codice di successo",
|
"codeSuccessTitle": "Codice di successo",
|
||||||
@ -1471,11 +1471,11 @@ export const messages= {
|
|||||||
"restartLoginTooltip": "Riavvia login",
|
"restartLoginTooltip": "Riavvia login",
|
||||||
"loginTotpIntro": "Devi impostare un generatore di OTP (password temporanea valida una volta sola) per accedere a questo account",
|
"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",
|
"loginTotpStep1": "Installa una delle seguenti applicazioni sul tuo dispositivo mobile",
|
||||||
"loginTotpStep2": "Apri l''applicazione e scansiona il codice QR",
|
"loginTotpStep2": "Apri l'applicazione e scansiona il codice QR",
|
||||||
"loginTotpStep3": "Scrivi il codice monouso fornito dall''applicazione e premi Invia per completare il setup",
|
"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.",
|
"loginTotpStep3DeviceName": "Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione.",
|
||||||
"loginTotpManualStep2": "Apri l''applicazione e scrivi la chiave",
|
"loginTotpManualStep2": "Apri l'applicazione e scrivi la chiave",
|
||||||
"loginTotpManualStep3": "Usa le seguenti impostazioni se l''applicazione lo consente",
|
"loginTotpManualStep3": "Usa le seguenti impostazioni se l'applicazione lo consente",
|
||||||
"loginTotpUnableToScan": "Non riesci a scansionare il codice QR?",
|
"loginTotpUnableToScan": "Non riesci a scansionare il codice QR?",
|
||||||
"loginTotpScanBarcode": "Vuoi scansionare il codice QR?",
|
"loginTotpScanBarcode": "Vuoi scansionare il codice QR?",
|
||||||
"loginCredential": "Credenziali",
|
"loginCredential": "Credenziali",
|
||||||
@ -1486,7 +1486,7 @@ export const messages= {
|
|||||||
"loginTotpInterval": "Intervallo",
|
"loginTotpInterval": "Intervallo",
|
||||||
"loginTotpCounter": "Contatore",
|
"loginTotpCounter": "Contatore",
|
||||||
"loginTotpDeviceName": "Nome del dispositivo di autenticazione",
|
"loginTotpDeviceName": "Nome del dispositivo di autenticazione",
|
||||||
"loginTotp.totp": "Basato sull''ora",
|
"loginTotp.totp": "Basato sull'ora",
|
||||||
"loginTotp.hotp": "Basato sul contatore",
|
"loginTotp.hotp": "Basato sul contatore",
|
||||||
"loginChooseAuthenticator": "Seleziona il tuo metodo di autenticazione",
|
"loginChooseAuthenticator": "Seleziona il tuo metodo di autenticazione",
|
||||||
"oauthGrantRequest": "Vuoi assegnare questi privilegi di accesso?",
|
"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?",
|
"emailVerifyInstruction2": "Non hai ricevuto un codice di verifica nella tua email?",
|
||||||
"emailVerifyInstruction3": "per rinviare la email.",
|
"emailVerifyInstruction3": "per rinviare la email.",
|
||||||
"emailLinkIdpTitle": "Collega {0}",
|
"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?",
|
"emailLinkIdp2": "Non hai ricevuto un codice di verifica nella tua email?",
|
||||||
"emailLinkIdp3": "Per rinviare la 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.",
|
"emailLinkIdp5": "per continuare.",
|
||||||
"backToLogin": "« Torna al Login",
|
"backToLogin": "« 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:",
|
"copyCodeInstruction": "Copia questo codice e incollalo nella tua applicazione:",
|
||||||
"pageExpiredTitle": "La pagina è scaduta",
|
"pageExpiredTitle": "La pagina è scaduta",
|
||||||
"pageExpiredMsg1": "Per ripetere il login",
|
"pageExpiredMsg1": "Per ripetere il login",
|
||||||
@ -1525,7 +1525,7 @@ export const messages= {
|
|||||||
"role_manage-events": "Gestisci eventi",
|
"role_manage-events": "Gestisci eventi",
|
||||||
"role_view-profile": "Visualizza profilo",
|
"role_view-profile": "Visualizza profilo",
|
||||||
"role_manage-account": "Gestisci account",
|
"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_read-token": "Leggi il token",
|
||||||
"role_offline-access": "Accesso offline",
|
"role_offline-access": "Accesso offline",
|
||||||
"client_account": "Account",
|
"client_account": "Account",
|
||||||
@ -1540,16 +1540,16 @@ export const messages= {
|
|||||||
"invalidUsernameOrEmailMessage": "Username o email non validi.",
|
"invalidUsernameOrEmailMessage": "Username o email non validi.",
|
||||||
"invalidPasswordMessage": "Password non valida.",
|
"invalidPasswordMessage": "Password non valida.",
|
||||||
"invalidEmailMessage": "Indirizzo email non valido.",
|
"invalidEmailMessage": "Indirizzo email non valido.",
|
||||||
"accountDisabledMessage": "L''account è disabilitato, contatta il tuo amministratore.",
|
"accountDisabledMessage": "L'account è disabilitato, contatta il tuo amministratore.",
|
||||||
"accountTemporarilyDisabledMessage": "L''account è temporaneamente disabilitato; contatta il tuo amministratore o prova più tardi.",
|
"accountTemporarilyDisabledMessage": "L'account è temporaneamente disabilitato; contatta il tuo amministratore o prova più tardi.",
|
||||||
"expiredCodeMessage": "Login scaduto. Riprovare.",
|
"expiredCodeMessage": "Login scaduto. Riprovare.",
|
||||||
"expiredActionMessage": "Azione scaduta. Continuare adesso con in login.",
|
"expiredActionMessage": "Azione scaduta. Continuare adesso con in login.",
|
||||||
"expiredActionTokenNoSessionMessage": "Azione scaduta.",
|
"expiredActionTokenNoSessionMessage": "Azione scaduta.",
|
||||||
"expiredActionTokenSessionExistsMessage": "Azione scaduta. Ricominciare.",
|
"expiredActionTokenSessionExistsMessage": "Azione scaduta. Ricominciare.",
|
||||||
"missingFirstNameMessage": "Inserisci il nome.",
|
"missingFirstNameMessage": "Inserisci il nome.",
|
||||||
"missingLastNameMessage": "Inserisci il cognome.",
|
"missingLastNameMessage": "Inserisci il cognome.",
|
||||||
"missingEmailMessage": "Inserisci l''email.",
|
"missingEmailMessage": "Inserisci l'email.",
|
||||||
"missingUsernameMessage": "Inserisci l''username.",
|
"missingUsernameMessage": "Inserisci l'username.",
|
||||||
"missingPasswordMessage": "Inserisci la password.",
|
"missingPasswordMessage": "Inserisci la password.",
|
||||||
"missingTotpMessage": "Inserisci il codice di autenticazione.",
|
"missingTotpMessage": "Inserisci il codice di autenticazione.",
|
||||||
"missingTotpDeviceNameMessage": "Inserisci il nome del dispositivo di autenticazione.",
|
"missingTotpDeviceNameMessage": "Inserisci il nome del dispositivo di autenticazione.",
|
||||||
@ -1560,12 +1560,12 @@ export const messages= {
|
|||||||
"invalidTotpMessage": "Codice di autenticazione non valido.",
|
"invalidTotpMessage": "Codice di autenticazione non valido.",
|
||||||
"usernameExistsMessage": "Username già esistente.",
|
"usernameExistsMessage": "Username già esistente.",
|
||||||
"emailExistsMessage": "Email 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",
|
"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}",
|
"federatedIdentityConfirmReauthenticateMessage": "Autenticati per associare il tuo account con {0}",
|
||||||
"confirmLinkIdpReviewProfile": "Rivedi profilo",
|
"confirmLinkIdpReviewProfile": "Rivedi profilo",
|
||||||
"confirmLinkIdpContinue": "Aggiungi all''account esistente",
|
"confirmLinkIdpContinue": "Aggiungi all'account esistente",
|
||||||
"configureTotpMessage": "Devi impostare un autenticatore per attivare il tuo account.",
|
"configureTotpMessage": "Devi impostare un autenticatore per attivare il tuo account.",
|
||||||
"updateProfileMessage": "Devi aggiornare il tuo profilo utente 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.",
|
"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.",
|
"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.",
|
"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.",
|
"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",
|
"httpsRequiredMessage": "HTTPS richiesto",
|
||||||
"realmNotEnabledMessage": "Realm non abilitato",
|
"realmNotEnabledMessage": "Realm non abilitato",
|
||||||
"invalidRequestMessage": "Richiesta non valida",
|
"invalidRequestMessage": "Richiesta non valida",
|
||||||
@ -1606,46 +1606,46 @@ export const messages= {
|
|||||||
"registrationNotAllowedMessage": "Registrazione non permessa",
|
"registrationNotAllowedMessage": "Registrazione non permessa",
|
||||||
"resetCredentialNotAllowedMessage": "Reimpostazione della credenziale non permessa",
|
"resetCredentialNotAllowedMessage": "Reimpostazione della credenziale non permessa",
|
||||||
"permissionNotApprovedMessage": "Permesso non approvato.",
|
"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à.",
|
"insufficientPermissionMessage": "Permessi insufficienti per associare le identità.",
|
||||||
"couldNotProceedWithAuthenticationRequestMessage": "Impossibile procedere con la 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.",
|
"couldNotObtainTokenMessage": "Non posso ottenere un token dall'identity provider.",
|
||||||
"unexpectedErrorRetrievingTokenMessage": "Errore inaspettato nel recupero del token dall''identity provider.",
|
"unexpectedErrorRetrievingTokenMessage": "Errore inaspettato nel recupero del token dall'identity provider.",
|
||||||
"unexpectedErrorHandlingResponseMessage": "Errore inaspettato nella gestione della risposta 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.",
|
"identityProviderAuthenticationFailedMessage": "Autenticazione fallita. Non posso effettuare l'autenticazione con l'identity provider.",
|
||||||
"couldNotSendAuthenticationRequestMessage": "Impossibile inviare la richiesta di autenticazione all''identity provider.",
|
"couldNotSendAuthenticationRequestMessage": "Impossibile inviare la richiesta di autenticazione all'identity provider.",
|
||||||
"unexpectedErrorHandlingRequestMessage": "Errore inaspettato nella gestione della richiesta di autenticazione all''identity provider.",
|
"unexpectedErrorHandlingRequestMessage": "Errore inaspettato nella gestione della richiesta di autenticazione all'identity provider.",
|
||||||
"invalidAccessCodeMessage": "Codice di accesso non valido.",
|
"invalidAccessCodeMessage": "Codice di accesso non valido.",
|
||||||
"sessionNotActiveMessage": "Sessione non attiva.",
|
"sessionNotActiveMessage": "Sessione non attiva.",
|
||||||
"invalidCodeMessage": "Si è verificato un errore, effettua di nuovo il login nella tua applicazione.",
|
"invalidCodeMessage": "Si è verificato un errore, effettua di nuovo il login nella tua applicazione.",
|
||||||
"identityProviderUnexpectedErrorMessage": "Errore imprevisto durante l''autenticazione con identity provider",
|
"identityProviderUnexpectedErrorMessage": "Errore imprevisto durante l'autenticazione con identity provider",
|
||||||
"identityProviderNotFoundMessage": "Non posso trovare un identity provider con l''identificativo.",
|
"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.",
|
"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.",
|
"realmSupportsNoCredentialsMessage": "Il realm non supporta nessun tipo di credenziali.",
|
||||||
"credentialSetupRequired": "Impossibile effettuare il login, è richiesto il setup delle 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.",
|
"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.",
|
"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?",
|
"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.",
|
"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.",
|
"confirmAccountLinking": "Conferma il collegamento per l'account {0} dell'identity provider {1} con il tuo account.",
|
||||||
"confirmEmailAddressVerification": "Conferma la validità dell''indirizzo email {0}.",
|
"confirmEmailAddressVerification": "Conferma la validità dell'indirizzo email {0}.",
|
||||||
"confirmExecutionOfActions": "Esegui la/le seguenti azione/i",
|
"confirmExecutionOfActions": "Esegui la/le seguenti azione/i",
|
||||||
"locale_it": "Italiano",
|
"locale_it": "Italiano",
|
||||||
"backToApplication": "« Torna all''applicazione",
|
"backToApplication": "« Torna all'applicazione",
|
||||||
"missingParameterMessage": "Parametri mancanti: {0}",
|
"missingParameterMessage": "Parametri mancanti: {0}",
|
||||||
"clientNotFoundMessage": "Client non trovato.",
|
"clientNotFoundMessage": "Client non trovato.",
|
||||||
"clientDisabledMessage": "Client disabilitato.",
|
"clientDisabledMessage": "Client disabilitato.",
|
||||||
"invalidParameterMessage": "Parametro non valido: {0}",
|
"invalidParameterMessage": "Parametro non valido: {0}",
|
||||||
"alreadyLoggedIn": "Sei già connesso.",
|
"alreadyLoggedIn": "Sei già connesso.",
|
||||||
"differentUserAuthenticated": "Se già autenticato con l''utente ''{0}'' in questa sessione. Per favore, fai prima il logout.",
|
"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.",
|
"brokerLinkingSessionExpired": "È stato richiesta un'associazione a un account broker, ma la sessione corrente non è più valida.",
|
||||||
"proceedWithAction": "» Clicca qui per continuare",
|
"proceedWithAction": "» Clicca qui per continuare",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Configura OTP",
|
"requiredAction.CONFIGURE_TOTP": "Configura OTP",
|
||||||
"requiredAction.terms_and_conditions": "Termini e condizioni",
|
"requiredAction.terms_and_conditions": "Termini e condizioni",
|
||||||
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
|
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
|
||||||
"requiredAction.UPDATE_PROFILE": "Aggiornamento profilo",
|
"requiredAction.UPDATE_PROFILE": "Aggiornamento profilo",
|
||||||
"requiredAction.VERIFY_EMAIL": "Verifica dell''indirizzo email",
|
"requiredAction.VERIFY_EMAIL": "Verifica dell'indirizzo email",
|
||||||
"doX509Login": "Sarai connesso come:",
|
"doX509Login": "Sarai connesso come:",
|
||||||
"clientCertificate": "Certificato client X509:",
|
"clientCertificate": "Certificato client X509:",
|
||||||
"noCertificate": "[Nessun certificato]",
|
"noCertificate": "[Nessun certificato]",
|
||||||
@ -1656,20 +1656,20 @@ export const messages= {
|
|||||||
"console-otp": "One-time password:",
|
"console-otp": "One-time password:",
|
||||||
"console-new-password": "Nuova password:",
|
"console-new-password": "Nuova password:",
|
||||||
"console-confirm-password": "Conferma 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-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-email-code": "Codice email:",
|
||||||
"console-accept-terms": "Accetti i termini? [y/n]:",
|
"console-accept-terms": "Accetti i termini? [y/n]:",
|
||||||
"console-accept": "y",
|
"console-accept": "y",
|
||||||
"openshift.scope.user_info": "Informazioni utente",
|
"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.user_full": "Accesso completo",
|
||||||
"openshift.scope.list-projects": "Elenca i progetti",
|
"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.message": "Reindirizzamento, attendere per favore.",
|
||||||
"saml.post-form.js-disabled": "JavaScript è disabilitato. È fortemente consigliato abilitarlo. Clicca sul bottone seguente per continuare.",
|
"saml.post-form.js-disabled": "JavaScript è disabilitato. È fortemente consigliato abilitarlo. Clicca sul bottone seguente per continuare.",
|
||||||
"otp-display-name": "Applicazione di autenticazione",
|
"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-display-name": "Password",
|
||||||
"password-help-text": "Accedi inserendo la tua password.",
|
"password-help-text": "Accedi inserendo la tua password.",
|
||||||
"auth-username-form-display-name": "Username",
|
"auth-username-form-display-name": "Username",
|
||||||
@ -1679,7 +1679,7 @@ export const messages= {
|
|||||||
"webauthn-display-name": "Chiave di sicurezza",
|
"webauthn-display-name": "Chiave di sicurezza",
|
||||||
"webauthn-help-text": "Utilizza la tua chiave di sicurezza per accedere.",
|
"webauthn-help-text": "Utilizza la tua chiave di sicurezza per accedere.",
|
||||||
"webauthn-passwordless-display-name": "Chiave di sicurezza",
|
"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-login-title": "Login con chiave di sicurezza",
|
||||||
"webauthn-registration-title": "Registrazione chiave di sicurezza",
|
"webauthn-registration-title": "Registrazione chiave di sicurezza",
|
||||||
"webauthn-available-authenticators": "Autenticatori disponibili",
|
"webauthn-available-authenticators": "Autenticatori disponibili",
|
||||||
@ -1687,7 +1687,7 @@ export const messages= {
|
|||||||
"webauthn-error-registration": "Impossibile registrare la tua chiave di sicurezza.",
|
"webauthn-error-registration": "Impossibile registrare la tua chiave di sicurezza.",
|
||||||
"webauthn-error-api-get": "Autenticazione con la chiave di sicurezza fallita.",
|
"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-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-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.",
|
"webauthn-error-user-not-found": "Utente sconosciuto autenticato con la chiave di sicurezza.",
|
||||||
"identity-provider-redirector": "Connettiti con un altro identity provider."
|
"identity-provider-redirector": "Connettiti con un altro identity provider."
|
||||||
@ -1960,7 +1960,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "クライアントが無効になっています。",
|
"clientDisabledMessage": "クライアントが無効になっています。",
|
||||||
"invalidParameterMessage": "無効なパラメーター: {0}",
|
"invalidParameterMessage": "無効なパラメーター: {0}",
|
||||||
"alreadyLoggedIn": "既にログインしています。",
|
"alreadyLoggedIn": "既にログインしています。",
|
||||||
"differentUserAuthenticated": "すでにこのセッションで異なるユーザー''{0}''として認証されています。まずログアウトしてください。",
|
"differentUserAuthenticated": "すでにこのセッションで異なるユーザー'{0}'として認証されています。まずログアウトしてください。",
|
||||||
"brokerLinkingSessionExpired": "要求されたブローカー・アカウントのリンクは、現在のセッションでは有効ではありません。",
|
"brokerLinkingSessionExpired": "要求されたブローカー・アカウントのリンクは、現在のセッションでは有効ではありません。",
|
||||||
"proceedWithAction": "» 続行するにはここをクリックしてください",
|
"proceedWithAction": "» 続行するにはここをクリックしてください",
|
||||||
"requiredAction.CONFIGURE_TOTP": "OTPの設定",
|
"requiredAction.CONFIGURE_TOTP": "OTPの設定",
|
||||||
@ -2920,7 +2920,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "Klient nieaktywny.",
|
"clientDisabledMessage": "Klient nieaktywny.",
|
||||||
"invalidParameterMessage": "Nieprawidłowy parametr: {0}",
|
"invalidParameterMessage": "Nieprawidłowy parametr: {0}",
|
||||||
"alreadyLoggedIn": "Jesteś już zalogowany.",
|
"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.",
|
"brokerLinkingSessionExpired": "Żądano łączenia kont brokera, ale bieżąca sesja już jest nieważna.",
|
||||||
"proceedWithAction": "» kliknij tutaj, aby przejść",
|
"proceedWithAction": "» kliknij tutaj, aby przejść",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Skonfiguruj OTP",
|
"requiredAction.CONFIGURE_TOTP": "Skonfiguruj OTP",
|
||||||
@ -3211,7 +3211,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "Cliente desativado.",
|
"clientDisabledMessage": "Cliente desativado.",
|
||||||
"invalidParameterMessage": "Parâmentro inválido: {0}",
|
"invalidParameterMessage": "Parâmentro inválido: {0}",
|
||||||
"alreadyLoggedIn": "Você já está logado.",
|
"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.",
|
"brokerLinkingSessionExpired": "Vinculação de conta do provedor de identidade solicitada, mas a sessão atual não é mais válida.",
|
||||||
"proceedWithAction": "» Clique aqui para continuar",
|
"proceedWithAction": "» Clique aqui para continuar",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Configurar OTP",
|
"requiredAction.CONFIGURE_TOTP": "Configurar OTP",
|
||||||
@ -3676,7 +3676,7 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "Klient bol zneplatnený.",
|
"clientDisabledMessage": "Klient bol zneplatnený.",
|
||||||
"invalidParameterMessage": "Neplatný parameter : {0}",
|
"invalidParameterMessage": "Neplatný parameter : {0}",
|
||||||
"alreadyLoggedIn": "Už ste prihlásený.",
|
"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á.",
|
"brokerLinkingSessionExpired": "Požadované prepojenie s účtom brokera, ale aktuálna relácia už nie je platná.",
|
||||||
"proceedWithAction": "» Ak chcete pokračovať, kliknite sem",
|
"proceedWithAction": "» Ak chcete pokračovať, kliknite sem",
|
||||||
"requiredAction.CONFIGURE_TOTP": "Konfigurácia OTP",
|
"requiredAction.CONFIGURE_TOTP": "Konfigurácia OTP",
|
||||||
@ -3895,7 +3895,7 @@ export const messages= {
|
|||||||
"doImpersonate": "Kişiselleştir",
|
"doImpersonate": "Kişiselleştir",
|
||||||
"kerberosNotConfigured": "Kerberos Tanımlanmamış",
|
"kerberosNotConfigured": "Kerberos Tanımlanmamış",
|
||||||
"kerberosNotConfiguredTitle": "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.",
|
"kerberosNotSetUp": "Kerberos kurulmadı. Giriş yapamazsın.",
|
||||||
"registerTitle": "Kayıt ol",
|
"registerTitle": "Kayıt ol",
|
||||||
"loginTitle": "{0} adresinde oturum açın",
|
"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.",
|
"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",
|
"loginTotpStep1": "Cep telefonunuzda aşağıdaki uygulamalardan birini yükleyin",
|
||||||
"loginTotpStep2": "Uygulamayı açın ve barkodu tarayın",
|
"loginTotpStep2": "Uygulamayı açı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ı açın ve anahtarı girin",
|
"loginTotpManualStep2": "Uygulamayı açın ve anahtarı girin",
|
||||||
"loginTotpManualStep3": "Uygulama bunları ayarlamaya izin veriyorsa aşağıdaki yapılandırma değerlerini kullanın.",
|
"loginTotpManualStep3": "Uygulama bunları ayarlamaya izin veriyorsa aşağıdaki yapılandırma değerlerini kullanın.",
|
||||||
"loginTotpUnableToScan": "Taranamıyor?",
|
"loginTotpUnableToScan": "Taranamıyor?",
|
||||||
@ -3984,7 +3984,7 @@ export const messages= {
|
|||||||
"emailLinkIdp3": "e-postayı yeniden göndermek için.",
|
"emailLinkIdp3": "e-postayı yeniden göndermek için.",
|
||||||
"emailLinkIdp4": "E-postayı farklı tarayıcıda zaten doğruladıysanız",
|
"emailLinkIdp4": "E-postayı farklı tarayıcıda zaten doğruladıysanız",
|
||||||
"emailLinkIdp5": "devam etmek.",
|
"emailLinkIdp5": "devam etmek.",
|
||||||
"backToLogin": "« Giriş''e geri dön",
|
"backToLogin": "« 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.",
|
"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:",
|
"copyCodeInstruction": "Lütfen bu kodu kopyalayın ve uygulamanıza yapıştırın:",
|
||||||
"pageExpiredTitle": "Sayfanın Süresi Doldu",
|
"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?",
|
"federatedIdentityConfirmLinkMessage": "{0} {1} kullanıcı zaten var. Nasıl devam etmek istersin?",
|
||||||
"confirmLinkIdpReviewProfile": "Profili gözden geçir",
|
"confirmLinkIdpReviewProfile": "Profili gözden geçir",
|
||||||
"confirmLinkIdpContinue": "Mevcut hesaba ekle",
|
"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.",
|
"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.",
|
"updatePasswordMessage": "Hesabınızı etkinleştirmek için şifrenizi değiştirmeniz gerekiyor.",
|
||||||
"resetPasswordMessage": "Şifreni değiştirmelisin.",
|
"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",
|
"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.",
|
"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.",
|
"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",
|
"unsupportedNameIdFormatMessage": "Desteklenmeyen NameIDFormat",
|
||||||
"invalidRequesterMessage": "Geçersiz istek",
|
"invalidRequesterMessage": "Geçersiz istek",
|
||||||
"registrationNotAllowedMessage": "Kayıt yapılamaz",
|
"registrationNotAllowedMessage": "Kayıt yapılamaz",
|
||||||
@ -4131,14 +4131,14 @@ export const messages= {
|
|||||||
"clientDisabledMessage": "İstemci engelli.",
|
"clientDisabledMessage": "İstemci engelli.",
|
||||||
"invalidParameterMessage": "Geçersiz Paremetreler: {0}",
|
"invalidParameterMessage": "Geçersiz Paremetreler: {0}",
|
||||||
"alreadyLoggedIn": "Zaten giriş yaptınız.",
|
"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.",
|
"brokerLinkingSessionExpired": "İstenen broker hesabı bağlanıyor, ancak mevcut oturum artık geçerli değil.",
|
||||||
"proceedWithAction": "» Devam etmek için buraya tıklayın",
|
"proceedWithAction": "» Devam etmek için buraya tıklayın",
|
||||||
"requiredAction.CONFIGURE_TOTP": "OTP Ayarla",
|
"requiredAction.CONFIGURE_TOTP": "OTP Ayarla",
|
||||||
"requiredAction.terms_and_conditions": "Şartlar ve Koşullar",
|
"requiredAction.terms_and_conditions": "Şartlar ve Koşullar",
|
||||||
"requiredAction.UPDATE_PASSWORD": "Şifre güncelle",
|
"requiredAction.UPDATE_PASSWORD": "Şifre güncelle",
|
||||||
"requiredAction.UPDATE_PROFILE": "Profili 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:",
|
"doX509Login": "Olarak giriş yapacaksınız:",
|
||||||
"clientCertificate": "X509 istemci sertifikası:",
|
"clientCertificate": "X509 istemci sertifikası:",
|
||||||
"noCertificate": "[Sertifika Yok]",
|
"noCertificate": "[Sertifika Yok]",
|
||||||
@ -4360,5 +4360,5 @@ export const messages= {
|
|||||||
"invalidParameterMessage": "无效的参数 : {0}",
|
"invalidParameterMessage": "无效的参数 : {0}",
|
||||||
"alreadyLoggedIn": "您已经登录"
|
"alreadyLoggedIn": "您已经登录"
|
||||||
}
|
}
|
||||||
} as const;
|
};
|
||||||
/* spell-checker: enable */
|
/* spell-checker: enable */
|
33
src/lib/i18n/kcMessages/login.ts
Normal file
33
src/lib/i18n/kcMessages/login.ts
Normal 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 };
|
||||||
|
|
@ -1,13 +1,23 @@
|
|||||||
|
|
||||||
import { createUseGlobalState } from "powerhooks";
|
import { createUseGlobalState } from "powerhooks";
|
||||||
import { kcContext } from "../kcContext";
|
import { kcContext } from "../KcContext";
|
||||||
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
|
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
|
||||||
|
|
||||||
export const { useKcLanguageTag } = createUseGlobalState(
|
//export const { useKcLanguageTag, evtKcLanguageTag } = createUseGlobalState(
|
||||||
|
const wrap = createUseGlobalState(
|
||||||
"kcLanguageTag",
|
"kcLanguageTag",
|
||||||
() => getBestMatchAmongKcLanguageTag(
|
() => getBestMatchAmongKcLanguageTag(
|
||||||
kcContext?.locale?.["current" as never] ??
|
kcContext?.locale?.current ??
|
||||||
navigator.language
|
navigator.language
|
||||||
),
|
),
|
||||||
{ "persistance": "cookies" }
|
{ "persistance": "localStorage" }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const { useKcLanguageTag } = wrap;
|
||||||
|
|
||||||
|
export function getEvtKcLanguage() {
|
||||||
|
return wrap.evtKcLanguageTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
51
src/lib/i18n/useKcMessage.tsx
Normal file
51
src/lib/i18n/useKcMessage.tsx
Normal 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 };
|
||||||
|
|
||||||
|
}
|
@ -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 };
|
|
||||||
|
|
||||||
}
|
|
@ -1,10 +1,21 @@
|
|||||||
export * from "./kcContext";
|
export * from "./KcContext";
|
||||||
|
|
||||||
export * from "./i18n/KcLanguageTag";
|
export * from "./i18n/KcLanguageTag";
|
||||||
export * from "./i18n/useKcLanguageTag";
|
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/Login";
|
||||||
export * from "./components/Template";
|
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";
|
@ -1,72 +1,215 @@
|
|||||||
|
|
||||||
import { ftlValuesGlobalName } from "../bin/build-keycloak-theme/ftlValuesGlobalName";
|
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 { 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 = {
|
/** Take theses type definition with a grain of salt.
|
||||||
pageBasename: Parameters<ReturnType<typeof generateFtlFilesCodeFactory>["generateFtlFilesCode"]>[0]["pageBasename"];
|
* Some values might be undefined on some pages.
|
||||||
url: {
|
* (ex: url.loginAction is undefined on error.ftl)
|
||||||
loginAction: string;
|
*/
|
||||||
resourcesPath: string;
|
export type KcContext =
|
||||||
resourcesCommonPath: string;
|
KcContext.Login | KcContext.Register | KcContext.Info |
|
||||||
loginRestartFlowUrl: string;
|
KcContext.Error | KcContext.LoginResetPassword | KcContext.LoginVerifyEmail |
|
||||||
loginResetCredentialsUrl: string;
|
KcContext.Terms | KcContext.LoginOtp | KcContext.LoginUpdateProfile |
|
||||||
registrationUrl: string;
|
KcContext.LoginIdpLinkConfirm;
|
||||||
};
|
|
||||||
realm: {
|
export declare namespace KcContext {
|
||||||
displayName?: string;
|
|
||||||
displayNameHtml?: string;
|
export type Common = {
|
||||||
internationalizationEnabled: boolean;
|
url: {
|
||||||
password: boolean;
|
loginAction: string;
|
||||||
loginWithEmailAllowed: boolean;
|
resourcesPath: string;
|
||||||
registrationEmailAsUsername: boolean;
|
resourcesCommonPath: string;
|
||||||
rememberMe: boolean;
|
loginRestartFlowUrl: string;
|
||||||
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?: {
|
|
||||||
loginUrl: string;
|
loginUrl: string;
|
||||||
alias: string;
|
};
|
||||||
providerId: string;
|
realm: {
|
||||||
displayName: string;
|
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: {
|
export type Login = Common & {
|
||||||
username?: string;
|
pageId: "login.ftl";
|
||||||
rememberMe: boolean;
|
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[];
|
||||||
|
social: {
|
||||||
|
displayInfo: boolean;
|
||||||
|
providers?: {
|
||||||
|
loginUrl: string;
|
||||||
|
alias: string;
|
||||||
|
providerId: string;
|
||||||
|
displayName: 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; }[];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LoginUpdateProfile = Common & {
|
||||||
|
pageId: "login-update-profile.ftl";
|
||||||
|
user: {
|
||||||
|
editUsernameAllowed: boolean;
|
||||||
|
username?: string;
|
||||||
|
email?: string;
|
||||||
|
firstName?: string;
|
||||||
|
lastName?: string;
|
||||||
|
};
|
||||||
|
messagesPerField: {
|
||||||
|
printIfExists<T>(
|
||||||
|
key: "username" | "email" | "firstName" | "lastName",
|
||||||
|
x: T
|
||||||
|
): T | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LoginIdpLinkConfirm = Common & {
|
||||||
|
pageId: "login-idp-link-confirm.ftl";
|
||||||
|
idpAlias: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
doExtends<KcContext["pageId"], PageId>();
|
||||||
|
doExtends<PageId, KcContext["pageId"]>();
|
||||||
|
|
||||||
export const kcContext = id<KcContext | undefined>((window as any)[ftlValuesGlobalName]);
|
export const kcContext = id<KcContext | undefined>((window as any)[ftlValuesGlobalName]);
|
||||||
|
|
||||||
|
|
||||||
|
1
src/lib/kcContextMocks/index.ts
Normal file
1
src/lib/kcContextMocks/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./kcContextMocks";
|
252
src/lib/kcContextMocks/kcContextMocks.ts
Normal file
252
src/lib/kcContextMocks/kcContextMocks.ts
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
|
||||||
|
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"
|
||||||
|
],
|
||||||
|
"social": {
|
||||||
|
"displayInfo": true
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const kcLoginUpdateProfileContext: KcContext.LoginUpdateProfile = {
|
||||||
|
...kcCommonContext,
|
||||||
|
"pageId": "login-update-profile.ftl",
|
||||||
|
"user": {
|
||||||
|
"editUsernameAllowed": true,
|
||||||
|
"username": "anUsername",
|
||||||
|
"email": "foo@example.com",
|
||||||
|
"firstName": "aFirstName",
|
||||||
|
"lastName": "aLastName"
|
||||||
|
},
|
||||||
|
"messagesPerField": {
|
||||||
|
"printIfExists": () => undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const kcLoginIdpLinkConfirmContext: KcContext.LoginIdpLinkConfirm ={
|
||||||
|
...kcCommonContext,
|
||||||
|
"pageId": "login-idp-link-confirm.ftl",
|
||||||
|
"idpAlias": "FranceConnect"
|
||||||
|
};
|
6
src/lib/kcContextMocks/urlResourcesPath.ts
Normal file
6
src/lib/kcContextMocks/urlResourcesPath.ts
Normal 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");
|
118
src/lib/keycloakJsAdapter.ts
Normal file
118
src/lib/keycloakJsAdapter.ts
Normal 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": () => { } }
|
||||||
|
}
|
||||||
|
) as any;
|
||||||
|
|
||||||
|
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
2
src/lib/tools/assert.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
export { assert } from "evt/tools/typeSafety/assert";
|
@ -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 }
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
@ -9,8 +9,10 @@ import {
|
|||||||
setupSampleReactProject();
|
setupSampleReactProject();
|
||||||
|
|
||||||
generateKeycloakThemeResources({
|
generateKeycloakThemeResources({
|
||||||
"themeName": "onyxia-ui",
|
"themeName": "keycloakify-demo-app",
|
||||||
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
|
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
|
||||||
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme")
|
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
|
||||||
|
"urlPathname": "/keycloakify-demo-app/",
|
||||||
|
"urlOrigin": undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
setupSampleReactProject,
|
setupSampleReactProject,
|
||||||
sampleReactProjectDirPath
|
sampleReactProjectDirPath
|
||||||
@ -9,10 +10,15 @@ import { getProjectRoot } from "../bin/tools/getProjectRoot";
|
|||||||
|
|
||||||
setupSampleReactProject();
|
setupSampleReactProject();
|
||||||
|
|
||||||
|
const binDirPath= pathJoin(getProjectRoot(), "dist", "bin");
|
||||||
|
|
||||||
st.execSyncTrace(
|
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 }
|
{ "cwd": sampleReactProjectDirPath }
|
||||||
)
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
st.execSyncTrace(
|
||||||
|
`node ${pathJoin(binDirPath, "install-builtin-keycloak-themes")}`,
|
||||||
|
{ "cwd": sampleReactProjectDirPath }
|
||||||
|
);
|
@ -1,30 +1,47 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
replaceImportFromStaticInJsCode,
|
replaceImportsFromStaticInJsCode,
|
||||||
replaceImportFromStaticInCssCode,
|
replaceImportsInCssCode,
|
||||||
generateCssCodeToDefineGlobals
|
generateCssCodeToDefineGlobals
|
||||||
} from "../bin/build-keycloak-theme/replaceImportFromStatic";
|
} from "../bin/build-keycloak-theme/replaceImportFromStatic";
|
||||||
|
|
||||||
const { fixedJsCode } = replaceImportFromStaticInJsCode({
|
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
||||||
"ftlValuesGlobalName": "keycloakFtlValues",
|
|
||||||
"jsCode": `
|
"jsCode": `
|
||||||
function f() {
|
function f() {
|
||||||
return a.p + "static/js/" + ({}[e] || e) + "." + {
|
return a.p+"static/js/" + ({}[e] || e) + "." + {
|
||||||
3: "0664cdc0"
|
3: "0664cdc0"
|
||||||
}[e] + ".chunk.js"
|
}[e] + ".chunk.js"
|
||||||
}
|
}
|
||||||
|
|
||||||
function f2() {
|
function f2() {
|
||||||
return a.p +"static/js/" + ({}[e] || e) + "." + {
|
return a.p+"static/js/" + ({}[e] || e) + "." + {
|
||||||
3: "0664cdc0"
|
3: "0664cdc0"
|
||||||
}[e] + ".chunk.js"
|
}[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": `
|
"cssCode": `
|
||||||
|
|
||||||
.my-div {
|
.my-div {
|
||||||
@ -45,6 +62,6 @@ const { fixedCssCode, cssGlobalsToDefine } = replaceImportFromStaticInCssCode({
|
|||||||
console.log({ fixedCssCode, cssGlobalsToDefine });
|
console.log({ fixedCssCode, cssGlobalsToDefine });
|
||||||
|
|
||||||
|
|
||||||
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine });
|
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine, "urlPathname": "/" });
|
||||||
|
|
||||||
console.log({ cssCodeToPrependInHead });
|
console.log({ cssCodeToPrependInHead });
|
@ -8,7 +8,7 @@ export const sampleReactProjectDirPath = pathJoin(getProjectRoot(), "sample_reac
|
|||||||
export function setupSampleReactProject() {
|
export function setupSampleReactProject() {
|
||||||
|
|
||||||
downloadAndUnzip({
|
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
|
"destDirPath": sampleReactProjectDirPath
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user