mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-09 17:13:41 +00:00
feat(console): OIDC setup (#1272)
* feat: delete app * radio button mods, i18n * radio style, recommended flag * fix form, emitter, module, styles * app oidc * form value change * cleanup * app grid, new app detail, redirect, i18n * new uri format * seperate uris * cleanup export, create redirect * fix custom two way binding, switch * chore(deps): bump grpc from 1.24.3 to 1.24.5 in /console (#1287) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps): bump grpc from 1.24.3 to 1.24.5 in /console Bumps [grpc](https://github.com/grpc/grpc-node) from 1.24.3 to 1.24.5. - [Release notes](https://github.com/grpc/grpc-node/releases) - [Commits](https://github.com/grpc/grpc-node/compare/grpc@1.24.3...grpc@1.24.5) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/node from 14.14.22 to 14.14.28 in /console (#1286) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump @types/node from 14.14.22 to 14.14.28 in /console Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.22 to 14.14.28. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular-devkit/build-angular from 0.1101.2 to 0.1102.0 in /console (#1285) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump @angular-devkit/build-angular in /console Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1101.2 to 0.1102.0. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/commits) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump typescript from 4.0.5 to 4.0.7 in /console (#1284) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump typescript from 4.0.5 to 4.0.7 in /console Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.0.5 to 4.0.7. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v4.0.5...v4.0.7) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump karma from 6.0.3 to 6.1.1 in /console (#1283) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump karma from 6.0.3 to 6.1.1 in /console Bumps [karma](https://github.com/karma-runner/karma) from 6.0.3 to 6.1.1. - [Release notes](https://github.com/karma-runner/karma/releases) - [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md) - [Commits](https://github.com/karma-runner/karma/compare/v6.0.3...v6.1.1) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/language-service from 11.1.1 to 11.2.0 in /console (#1282) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump @angular/language-service in /console Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.1.1 to 11.2.0. - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/11.2.0/packages/language-service) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump stylelint from 13.9.0 to 13.10.0 in /console (#1281) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump stylelint from 13.9.0 to 13.10.0 in /console Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.9.0 to 13.10.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/13.9.0...13.10.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/cli from 11.1.2 to 11.2.0 in /console (#1280) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump @angular/cli from 11.1.2 to 11.2.0 in /console Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.1.2 to 11.2.0. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/compare/v11.1.2...v11.2.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump stylelint-scss from 3.18.0 to 3.19.0 in /console (#1279) * chore: add local migrate_local.go again (#1261) * chore: pass params in migrate_local.go (#1264) * fix: login policy bug (#1268) * fix: permissions on login policy multifactors and secondfactors * fix idp restriction Co-authored-by: Max Peintner <max@caos.ch> * fix: redirect after idp create (#1269) * fix(pipeline): corrected and combined operator and zitadel release into combined workflow (#1273) * fix(pipeline): combined operator and zitadel workflow to only release once * fix(pipeline): add dev releases for zitadelctl * fix(pipeline): delete unused name attribute * fix(pipeline): corrected use of github token env-variable * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected download of artifacts to globally defined folder * fix(pipeline): corrected ref to get branch name for release * fix(pipeline): last corrections and use of different github action (#1270) * fix(pipeline): corrected loop for dev release * fix(pipeline): exclude tags from starting build workflow * fix(pipeline): use different release create action for already existing release * fix(pipeline): use correct name for release * fix(pipeline): push image with branch name tag and replace slashes with underscores * fix(pipeline): corrected indenting for yaml syntax * fix(pipeline): corrected handling of branch name * fix(pipeline): list artifacts after download * fix(pipeline): use github env for artifacts folder * fix(pipeline): replace slash with underscore in all jobs * fix(pipeline): pre-calculate refs for all jobs * fix(pipeline): corrected yaml indenting * fix(pipeline): deleted missed step * fix(pipeline): deleted unexpected input for dev-release * fix(pipeline): corrected echo for version in refs job * fix(pipeline): remove empty if in job * chore(pipeline): use correct path to zitadelctl binaries (#1277) * fix(pipeline): use correct version for zitadelctl build (#1278) * chore(deps-dev): bump stylelint-scss from 3.18.0 to 3.19.0 in /console Bumps [stylelint-scss](https://github.com/kristerkari/stylelint-scss) from 3.18.0 to 3.19.0. - [Release notes](https://github.com/kristerkari/stylelint-scss/releases) - [Changelog](https://github.com/kristerkari/stylelint-scss/blob/master/CHANGELOG.md) - [Commits](https://github.com/kristerkari/stylelint-scss/compare/3.18.0...3.19.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix custom change, highlight current config, links * info app-detail * app card component * applications list, fix project-grant-owner * fix member write * colorize warn in app * redirect warnings * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/en.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * remove comments * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update console/src/assets/i18n/de.json Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
This commit is contained in:
parent
f01921371c
commit
a555d6aaaf
3781
console/package-lock.json
generated
3781
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -33,7 +33,7 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"google-proto-files": "^2.4.0",
|
||||
"google-protobuf": "^3.13.0",
|
||||
"grpc": "^1.24.3",
|
||||
"grpc": "^1.24.5",
|
||||
"grpc-web": "^1.2.1",
|
||||
"moment": "^2.29.1",
|
||||
"ngx-quicklink": "^0.2.6",
|
||||
@ -44,28 +44,28 @@
|
||||
"zone.js": "~0.11.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "~11.1.2",
|
||||
"@angular-devkit/build-angular": "~0.1101.2",
|
||||
"@angular/cli": "~11.2.0",
|
||||
"@angular-devkit/build-angular": "~0.1102.0",
|
||||
"@angular/compiler-cli": "~11.0.0",
|
||||
"@types/jasmine": "~3.6.3",
|
||||
"@angular/language-service": "~11.1.1",
|
||||
"@angular/language-service": "~11.2.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^14.14.22",
|
||||
"@types/node": "^14.14.28",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.6.0",
|
||||
"jasmine-spec-reporter": "~6.0.0",
|
||||
"karma": "~6.0.3",
|
||||
"karma": "~6.1.1",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"prettier": "^2.2.1",
|
||||
"protractor": "~7.0.0",
|
||||
"stylelint": "^13.9.0",
|
||||
"stylelint": "^13.10.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"stylelint-scss": "^3.18.0",
|
||||
"stylelint-scss": "^3.19.0",
|
||||
"ts-node": "~9.1.1",
|
||||
"tslint": "~6.1.3",
|
||||
"typescript": "^4.0.5"
|
||||
"typescript": "^4.0.7"
|
||||
}
|
||||
}
|
||||
|
5
console/src/app/modules/app-card/app-card.component.html
Normal file
5
console/src/app/modules/app-card/app-card.component.html
Normal file
@ -0,0 +1,5 @@
|
||||
<div class="cnsl-app-card" [ngClass]="{'web': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
|
||||
'useragent': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
|
||||
'native': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE}">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
49
console/src/app/modules/app-card/app-card.component.scss
Normal file
49
console/src/app/modules/app-card/app-card.component.scss
Normal file
@ -0,0 +1,49 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin app-card-theme($theme) {
|
||||
/* stylelint-disable */
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-dark: mat-color($primary, A900);
|
||||
$accent: map-get($theme, accent);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$accent-color: mat-color($primary, 500);
|
||||
/* stylelint-enable */
|
||||
|
||||
.cnsl-app-card {
|
||||
padding: 1rem;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
animation: all .2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 2rem;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
margin: 1rem;
|
||||
text-transform: uppercase;
|
||||
border-radius: .5rem;
|
||||
font-weight: 800;
|
||||
background-color: $primary-dark;
|
||||
transition: background-color box-shadow .3s ease-in;
|
||||
|
||||
&.web {
|
||||
background-color: rgb(80, 110, 110);
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.native {
|
||||
background-color: #595d80;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.useragent {
|
||||
background-color: #6a506e;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
14
console/src/app/modules/app-card/app-card.component.ts
Normal file
14
console/src/app/modules/app-card/app-card.component.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-app-card',
|
||||
templateUrl: './app-card.component.html',
|
||||
styleUrls: ['./app-card.component.scss'],
|
||||
})
|
||||
export class AppCardComponent {
|
||||
@Input() public outline: boolean = false;
|
||||
@Input() public type!: OIDCApplicationType;
|
||||
|
||||
public OIDCApplicationType: any = OIDCApplicationType;
|
||||
}
|
15
console/src/app/modules/app-card/app-card.module.ts
Normal file
15
console/src/app/modules/app-card/app-card.module.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppCardComponent } from './app-card.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppCardComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
],
|
||||
exports: [
|
||||
AppCardComponent,
|
||||
],
|
||||
})
|
||||
export class AppCardModule { }
|
@ -0,0 +1,35 @@
|
||||
<div class="radio-button-wrapper">
|
||||
<ng-container *ngFor="let method of authMethods; index as i">
|
||||
<input type="radio" [disabled]="method.disabled" (change)="emitChange()" [value]="method.key" [id]="method.key"
|
||||
[(ngModel)]="selected" />
|
||||
<label class="cnsl-radio-button" [ngClass]="{'first': i == 0, 'last': i == authMethods.length - 1}"
|
||||
[for]="method.key">
|
||||
<div class="recommended" [ngClass]="{'not': method.notRecommended}"
|
||||
*ngIf="method.recommended || method.notRecommended">
|
||||
{{(method.recommended ?
|
||||
'APP.OIDC.RECOMMENDED' : 'APP.OIDC.NOTRECOMMENDED') | translate }}</div>
|
||||
|
||||
<div class="cnsl-radio-header" [ngStyle]="{'background': method.background}">
|
||||
<span>{{method.prefix}}</span>
|
||||
<div class="current" *ngIf="current == method.key">{{'APP.OIDC.CURRENT' | translate}}</div>
|
||||
</div>
|
||||
<p>{{method.titleI18nKey | translate}}</p>
|
||||
<p class="type-desc">{{method.descI18nKey | translate}}</p>
|
||||
<span class="fill-space"></span>
|
||||
<div class="app-specs">
|
||||
<div class="row" *ngIf="method && method.responseType != undefined">
|
||||
<span>{{'APP.OIDC.RESPONSE' | translate}}</span>
|
||||
<span>{{('APP.OIDC.RESPONSE'+method.responseType.toString()) | translate}}</span>
|
||||
</div>
|
||||
<div class="row" *ngIf="method.grantType != undefined">
|
||||
<span>{{'APP.GRANT' | translate}}</span>
|
||||
<span>{{('APP.OIDC.GRANT'+method.grantType.toString()) | translate}}</span>
|
||||
</div>
|
||||
<div class="row" *ngIf="method.authMethod != undefined">
|
||||
<span>{{'APP.OIDC.AUTHMETHOD' | translate}}</span>
|
||||
<span>{{('APP.OIDC.AUTHMETHOD'+method.authMethod.toString()) | translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</ng-container>
|
||||
</div>
|
@ -0,0 +1,140 @@
|
||||
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
.radio-button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin: 0;
|
||||
padding-bottom: .5rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
@mixin app-auth-method-radio-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat-color($primary, 500);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
|
||||
input[type="radio"]{
|
||||
appearance: none;
|
||||
opacity: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
input:checked + label {
|
||||
border-color: if($is-dark-theme, white, var(--grey));
|
||||
|
||||
.cnsl-radio-header span {
|
||||
color: if($is-dark-theme, white, white);
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-radio-button {
|
||||
margin: .5rem;
|
||||
border-radius: .5rem;
|
||||
border: 1px solid if($is-dark-theme, var(--grey), white);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 0 1 230px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-bottom: 1rem;
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
||||
|
||||
&.first {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.recommended {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateY(50%) translateX(-50%);
|
||||
border-radius: 50vw;
|
||||
font-size: 11px;
|
||||
background: white;
|
||||
color: black;
|
||||
padding: 3px 1rem;
|
||||
box-shadow: 0 0 6px rgb(0 0 0 / 10%);
|
||||
white-space: nowrap;
|
||||
|
||||
&.not {
|
||||
background: rgb(144 75 75);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-radio-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
background: rgb(80, 110, 110);
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
position: relative;
|
||||
|
||||
.current {
|
||||
position: absolute;
|
||||
bottom: .5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: block;
|
||||
color: #ffffff60;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 2rem;
|
||||
font-size: 30px;
|
||||
color: if($is-dark-theme,#21222450, #ffffff50);
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.type-desc {
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.app-specs {
|
||||
display: block;
|
||||
padding: 1rem 0;
|
||||
margin: 0 1rem;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--grey);
|
||||
margin: 3px 0;
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:first-child {
|
||||
margin-right: 1rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { OIDCAuthMethodType, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
|
||||
|
||||
export interface RadioItemAuthType {
|
||||
key: string;
|
||||
titleI18nKey: string;
|
||||
descI18nKey: string;
|
||||
disabled: boolean,
|
||||
prefix: string;
|
||||
background: string;
|
||||
responseType?: OIDCResponseType;
|
||||
grantType?: OIDCGrantType;
|
||||
authMethod?: OIDCAuthMethodType;
|
||||
recommended?: boolean;
|
||||
notRecommended?: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-auth-method-radio',
|
||||
templateUrl: './app-auth-method-radio.component.html',
|
||||
styleUrls: ['./app-auth-method-radio.component.scss'],
|
||||
})
|
||||
export class AppAuthMethodRadioComponent {
|
||||
@Input() current: string = '';
|
||||
@Input() selected: string = '';
|
||||
@Input() authMethods!: RadioItemAuthType[];
|
||||
@Output() selectedMethod: EventEmitter<string> = new EventEmitter();
|
||||
|
||||
public emitChange(): void {
|
||||
this.selectedMethod.emit(this.selected);
|
||||
}
|
||||
}
|
27
console/src/app/modules/app-radio/app-radio.module.ts
Normal file
27
console/src/app/modules/app-radio/app-radio.module.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { AppAuthMethodRadioComponent } from './app-auth-method-radio/app-auth-method-radio.component';
|
||||
import { AppTypeRadioComponent } from './app-type-radio/app-type-radio.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppTypeRadioComponent,
|
||||
AppAuthMethodRadioComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatRippleModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [
|
||||
AppAuthMethodRadioComponent,
|
||||
AppTypeRadioComponent,
|
||||
],
|
||||
})
|
||||
export class AppRadioModule { }
|
||||
|
@ -0,0 +1,14 @@
|
||||
<div class="radio-button-wrapper">
|
||||
<ng-container *ngFor="let type of types">
|
||||
<input type="radio" [disabled]="type.disabled" (change)="emitChange()" [value]="type.type"
|
||||
[(ngModel)]="selected" [id]="type.type" />
|
||||
<label class="cnsl-type-radio-button" [for]="type.type">
|
||||
<div class="cnsl-type-radio-header" [ngStyle]="{'background': type.background}">
|
||||
<span>{{type.prefix}}</span>
|
||||
</div>
|
||||
<p>{{type.titleI18nKey | translate}}</p>
|
||||
<p class="type-desc">{{type.descI18nKey | translate}}</p>
|
||||
<span class="fill-space"></span>
|
||||
</label>
|
||||
</ng-container>
|
||||
</div>
|
@ -0,0 +1,68 @@
|
||||
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
.radio-button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -0.5rem;
|
||||
}
|
||||
|
||||
@mixin app-type-radio-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat-color($primary, 500);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
|
||||
input[type="radio"]{
|
||||
appearance: none;
|
||||
opacity: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
input:checked + label {
|
||||
border-color: if($is-dark-theme, white, var(--grey));
|
||||
|
||||
.cnsl-type-radio-header span {
|
||||
color: if($is-dark-theme, white, white);
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-type-radio-button {
|
||||
margin: .5rem;
|
||||
border-radius: .5rem;
|
||||
border: 1px solid if($is-dark-theme, var(--grey), white);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 0 1 240px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
padding-bottom: 1rem;
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
||||
|
||||
.cnsl-type-radio-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgb(80, 110, 110);
|
||||
margin-bottom: 1rem;
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
|
||||
span {
|
||||
margin: 2rem;
|
||||
font-size: 30px;
|
||||
color: if($is-dark-theme,#21222450, #ffffff50);
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.type-desc {
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
|
||||
|
||||
export interface RadioItemAppType {
|
||||
type: OIDCApplicationType;
|
||||
titleI18nKey: string;
|
||||
descI18nKey: string;
|
||||
checked: boolean,
|
||||
disabled: boolean,
|
||||
prefix: string;
|
||||
background: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-type-radio',
|
||||
templateUrl: './app-type-radio.component.html',
|
||||
styleUrls: ['./app-type-radio.component.scss'],
|
||||
})
|
||||
export class AppTypeRadioComponent {
|
||||
@Input() selected: OIDCApplicationType = OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB;
|
||||
@Input() types!: RadioItemAppType[];
|
||||
@Output() selectedType: EventEmitter<OIDCApplicationType> = new EventEmitter();
|
||||
|
||||
public emitChange(): void {
|
||||
this.selectedType.emit(this.selected);
|
||||
}
|
||||
}
|
@ -4,7 +4,8 @@
|
||||
<h2 class="title">{{title}}</h2>
|
||||
<span class="fill-space"></span>
|
||||
<ng-content select="[card-actions]"></ng-content>
|
||||
<button class="button" matTooltip="Expand or collapse" mat-icon-button (click)="expanded = !expanded">
|
||||
<button class="button" type="button" matTooltip="Expand or collapse" mat-icon-button
|
||||
(click)="expanded = !expanded">
|
||||
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
|
||||
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>
|
||||
</button>
|
||||
|
@ -24,6 +24,8 @@
|
||||
font-size: 16px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .05em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
|
@ -18,7 +18,7 @@ import { Component, Input } from '@angular/core';
|
||||
],
|
||||
})
|
||||
export class CardComponent {
|
||||
public expanded: boolean = true;
|
||||
@Input() public expanded: boolean = true;
|
||||
@Input() public title: string = '';
|
||||
@Input() public description: string = '';
|
||||
@Input() public animate: boolean = false;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<div class="info-section-row">
|
||||
<i class="icon las la-info"></i>
|
||||
<div class="info-section-row" [ngClass]="{'info': type == 'INFO', 'warn': type == 'WARN'}">
|
||||
<i *ngIf="type == 'INFO'" class="icon las la-info"></i>
|
||||
<i *ngIf="type == 'WARN'" class="las la-exclamation"></i>
|
||||
|
||||
<div class="info-section-content">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
@ -7,24 +7,36 @@
|
||||
|
||||
.info-section-row {
|
||||
display: flex;
|
||||
background-color: if($is-dark-theme, #ffffff13, #f3f3f3);
|
||||
border-radius: 4px;
|
||||
padding: .5rem 0;
|
||||
padding-right: 1rem;
|
||||
color: if($is-dark-theme, #d6d6d6, #3c4257);
|
||||
font-size: 14px;
|
||||
|
||||
.icon {
|
||||
margin-right: 1rem;
|
||||
height: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
font-size: 1.2rem;
|
||||
margin-left: .5rem;
|
||||
color: $primary-color;
|
||||
margin-right: 1rem;
|
||||
height: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
font-size: 1.2rem;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
|
||||
.info-section-content {
|
||||
flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&.info {
|
||||
background-color: if($is-dark-theme, #4f566b, #cbf4c9);
|
||||
color: if($is-dark-theme, #cbf4c9, #0e6245);
|
||||
|
||||
.icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.warn {
|
||||
background-color: if($is-dark-theme, #4f566b, #ffc1c1);
|
||||
color: if($is-dark-theme, #ffc1c1, #620e0e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
enum InfoSectionType {
|
||||
INFO = 'INFO',
|
||||
WARN = 'WARN',
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-info-section',
|
||||
templateUrl: './info-section.component.html',
|
||||
styleUrls: ['./info-section.component.scss'],
|
||||
})
|
||||
export class InfoSectionComponent { }
|
||||
export class InfoSectionComponent {
|
||||
|
||||
@Input() type = InfoSectionType.INFO;
|
||||
}
|
||||
|
@ -23,18 +23,14 @@
|
||||
<p class="step-title">{{'APP.OIDC.TITLEFIRST' | translate}}</p>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
<input cnslInput cdkFocusInitial formControlName="name" />
|
||||
<span cnsl-error *ngIf="name?.errors?.required">{{'PROJECT.APP.NAMEREQUIRED' | translate}}</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.TYPETITLE' | translate}}</p>
|
||||
<mat-radio-group color="primary" aria-labelledby="radio-group-label" class="radio-group"
|
||||
formControlName="applicationType">
|
||||
<mat-radio-button class="radio-button" *ngFor="let type of oidcAppTypes | keyvalue"
|
||||
[value]="type.value">
|
||||
<div>{{('APP.OIDC.APPTYPE'+type.key.toString()) | translate}}</div>
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
||||
<app-type-radio [types]="oidcAppTypes" (selectedType)="changedAppType($event)"
|
||||
[selected]="applicationType?.value"></app-type-radio>
|
||||
<div class="actions">
|
||||
<button mat-raised-button [disabled]="firstFormGroup.invalid" color="primary"
|
||||
matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
@ -42,37 +38,19 @@
|
||||
</form>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [editable]="true"
|
||||
*ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
|
||||
<ng-template matStepLabel>{{'APP.OIDC.RESPONSESECTION' | translate}}</ng-template>
|
||||
<div class="checkbox-container">
|
||||
<mat-checkbox class="checkbox" *ngFor="let responsetype of oidcResponseTypes"
|
||||
(change)="changeResponseType()" color="primary" [(ngModel)]="responsetype.checked"
|
||||
[disabled]="responsetype.disabled">
|
||||
{{'APP.OIDC.RESPONSE'+responsetype.type | translate}}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
||||
<button mat-raised-button color="primary" matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
<mat-step *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB"
|
||||
<!-- skip for native applications -->
|
||||
<mat-step *ngIf="oidcApp.applicationType !== OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE"
|
||||
[stepControl]="secondFormGroup" [editable]="true">
|
||||
<form [formGroup]="secondFormGroup">
|
||||
<ng-template matStepLabel>{{'APP.OIDC.AUTHMETHODSECTION' | translate}}</ng-template>
|
||||
|
||||
<mat-radio-group color="primary" aria-labelledby="example-radio-group-label" class="radio-group"
|
||||
formControlName="authMethodType">
|
||||
<mat-radio-button class="radio-button" *ngFor="let authmethod of oidcAuthMethodType"
|
||||
[disabled]="authmethod.disabled" [value]="authmethod.type">
|
||||
{{'APP.OIDC.AUTHMETHOD'+authmethod.type | translate}}
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
<app-auth-method-radio [authMethods]="authMethods" [selected]="authMethod?.value"
|
||||
(selectedMethod)="changedAppAuthMethod($event)">
|
||||
</app-auth-method-radio>
|
||||
|
||||
<div class="actions">
|
||||
<button mat-stroked-button color="primary"
|
||||
matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' |
|
||||
translate}}</button>
|
||||
<button mat-raised-button color="primary" [disabled]="secondFormGroup.invalid"
|
||||
matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
</div>
|
||||
@ -89,25 +67,10 @@
|
||||
<p class="step-description" *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<form class="chip-form" (ngSubmit)="addUri(redInput, 'REDIRECT')">
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label>
|
||||
<input #redInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
|
||||
[formControl]="redirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<mat-chip-list #chipRedirectList aria-label="uri selection">
|
||||
<mat-chip #redInput class="chip" *ngFor="let uri of oidcApp.redirectUrisList" selected removable
|
||||
[matTooltip]="!uri?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
[color]="!uri?.startsWith('https://') ? 'warn': 'white'" (removed)="removeUri(uri, 'REDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<p *ngIf="redirectControl.invalid" class="error">{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
(changedUris)="oidcApp.redirectUrisList = $event" [urisList]="oidcApp.redirectUrisList"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<p class="step-title">{{'APP.OIDC.POSTREDIRECTTITLE' | translate}}</p>
|
||||
<p class="step-description"
|
||||
@ -117,26 +80,10 @@
|
||||
*ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<form class="chip-form" (ngSubmit)="addUri(postInput, 'POSTREDIRECT')">
|
||||
<cnsl-form-field appearance="outline" class="full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
|
||||
<input #postInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
|
||||
[formControl]="postRedirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList"
|
||||
[matTooltip]="!uri?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
removable (removed)="removeUri(uri, 'POSTREDIRECT')" selected
|
||||
[color]="!uri?.startsWith('https://') ? 'warn': 'white'">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<p *ngIf="postRedirectControl.invalid" class="error">{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
(changedUris)="oidcApp.postLogoutRedirectUrisList = $event"
|
||||
[urisList]="oidcApp.postLogoutRedirectUrisList" title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<div class="actions">
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
||||
@ -171,9 +118,8 @@
|
||||
<span class="right" *ngIf="oidcApp.grantTypesList?.length > 0">
|
||||
[<span *ngFor="let element of oidcApp.grantTypesList; index as i">
|
||||
{{'APP.OIDC.GRANT'+element | translate}}
|
||||
{{i < oidcApp.grantTypesList.length - 1 ? ', ': ''}}
|
||||
</span>]
|
||||
</span>
|
||||
{{i < oidcApp.grantTypesList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left">
|
||||
@ -182,9 +128,8 @@
|
||||
<span class="right" *ngIf="oidcApp.responseTypesList?.length > 0">
|
||||
[<span *ngFor="let element of oidcApp.responseTypesList; index as i">
|
||||
{{('APP.OIDC.RESPONSE'+element | translate)}}
|
||||
{{i < oidcApp.responseTypesList.length - 1 ? ', ': ''}}
|
||||
</span>]
|
||||
</span>
|
||||
{{i < oidcApp.responseTypesList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@ -205,9 +150,8 @@
|
||||
<span class="right" *ngIf="oidcApp.redirectUrisList?.length > 0">
|
||||
[<span *ngFor="let redirect of oidcApp.redirectUrisList; index as i">
|
||||
{{redirect}}
|
||||
{{i < oidcApp.redirectUrisList.length - 1 ? ', ': ''}}
|
||||
</span>]
|
||||
</span>
|
||||
{{i < oidcApp.redirectUrisList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@ -217,15 +161,14 @@
|
||||
<span class="right" *ngIf="oidcApp.postLogoutRedirectUrisList?.length > 0">
|
||||
[<span *ngFor="let redirect of oidcApp.postLogoutRedirectUrisList; index as i">
|
||||
{{redirect}}
|
||||
{{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ': ''}}
|
||||
</span>]
|
||||
</span>
|
||||
{{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} </span>]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
||||
<button mat-raised-button color="primary"
|
||||
(click)="saveOIDCApp()">{{'ACTIONS.CREATE' | translate}}</button>
|
||||
<button mat-raised-button color="primary" (click)="saveOIDCApp()">{{'ACTIONS.CREATE' |
|
||||
translate}}</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-horizontal-stepper>
|
||||
@ -241,8 +184,8 @@
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'APP.OIDC.APPTYPE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="applicationType">
|
||||
<mat-option *ngFor="let type of oidcAppTypes" [value]="type">
|
||||
{{ 'APP.OIDC.APPTYPE'+type | translate }}
|
||||
<mat-option *ngFor="let type of oidcAppTypes" [value]="type.type">
|
||||
{{ 'APP.OIDC.APPTYPE'+type.type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
@ -274,32 +217,18 @@
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.redirectUrisList" removable
|
||||
(removed)="removeUri(uri, 'REDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input cnslInput [matChipInputFor]="chipRedirectList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addUri($event, 'REDIRECT')">
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipPostRedirectList aria-label="uri selection">
|
||||
<mat-chip class="chip" *ngFor="let uri of oidcApp.postLogoutRedirectUrisList" removable
|
||||
(removed)="removeUri(uri, 'POSTREDIRECT')">
|
||||
{{uri}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input cnslInput [matChipInputFor]="chipPostRedirectList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addUri($event, 'POSTREDIRECT')">
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
<div class="formfield full-width">
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
(changedUris)="oidcApp.redirectUrisList = $event" [urisList]="oidcApp.redirectUrisList"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="true"
|
||||
(changedUris)="oidcApp.postLogoutRedirectUrisList = $event"
|
||||
[urisList]="oidcApp.postLogoutRedirectUrisList"
|
||||
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" cdkFocusInitial
|
||||
|
@ -42,11 +42,6 @@ p.desc {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
width: 400px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
@ -55,6 +50,10 @@ p.desc {
|
||||
background: inherit !important;
|
||||
margin: 0 -1.5rem;
|
||||
|
||||
.formfield {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-size: 1rem;
|
||||
text-transform: uppercase;
|
||||
@ -65,44 +64,6 @@ p.desc {
|
||||
font-size: .9rem;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.chip-form {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 13px;
|
||||
color: #f44336;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.chip[color='white'] {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.radio-button {
|
||||
margin: .5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
@ -137,7 +98,6 @@ p.desc {
|
||||
float: right;
|
||||
margin-top: 1rem;
|
||||
border-radius: .5rem;
|
||||
padding: .5rem 1rem;
|
||||
min-width: 100px;
|
||||
}
|
||||
}
|
||||
@ -147,9 +107,11 @@ p.desc {
|
||||
display: flex;
|
||||
margin: 0 -.5rem;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
|
||||
.formfield {
|
||||
flex: 1 0 40%;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
margin: 0 .5rem;
|
||||
|
||||
&.full-width {
|
||||
@ -164,4 +126,4 @@ p.desc {
|
||||
padding: .5rem 4rem;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
|
||||
import {
|
||||
Application,
|
||||
OIDCApplicationCreate,
|
||||
@ -17,7 +18,15 @@ import {
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import {
|
||||
WEB_TYPE,
|
||||
NATIVE_TYPE,
|
||||
USER_AGENT_TYPE
|
||||
} from '../authtypes';
|
||||
|
||||
import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component';
|
||||
import { CODE_METHOD, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD } from '../authmethods';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-app-create',
|
||||
@ -37,10 +46,16 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
{ type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN, checked: false, disabled: false },
|
||||
];
|
||||
|
||||
public oidcAppTypes: OIDCApplicationType[] = [
|
||||
OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
|
||||
OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
|
||||
OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE,
|
||||
public oidcAppTypes: any = [
|
||||
WEB_TYPE,
|
||||
NATIVE_TYPE,
|
||||
USER_AGENT_TYPE,
|
||||
];
|
||||
|
||||
public authMethods: RadioItemAuthType[] = [
|
||||
PKCE_METHOD,
|
||||
CODE_METHOD,
|
||||
POST_METHOD,
|
||||
];
|
||||
|
||||
public oidcAuthMethodType: { type: OIDCAuthMethodType, checked: boolean, disabled: boolean; }[] = [
|
||||
@ -52,7 +67,6 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
// stepper
|
||||
firstFormGroup!: FormGroup;
|
||||
secondFormGroup!: FormGroup;
|
||||
// thirdFormGroup!: FormGroup;
|
||||
|
||||
// devmode
|
||||
public form!: FormGroup;
|
||||
@ -72,9 +86,6 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
// TODO show when implemented
|
||||
];
|
||||
|
||||
public redirectControl: FormControl = new FormControl('');
|
||||
public postRedirectControl: FormControl = new FormControl('');
|
||||
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
|
||||
constructor(
|
||||
@ -104,64 +115,58 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.firstFormGroup = this.fb.group({
|
||||
name: ['', [Validators.required]],
|
||||
applicationType: ['', [Validators.required]],
|
||||
applicationType: [OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, [Validators.required]],
|
||||
});
|
||||
|
||||
this.firstFormGroup.valueChanges.subscribe(value => {
|
||||
if (this.firstFormGroup.valid) {
|
||||
switch (value.applicationType) {
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
|
||||
this.oidcResponseTypes[0].checked = true;
|
||||
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||
|
||||
this.oidcApp.grantTypesList =
|
||||
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
|
||||
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||
|
||||
// this.redirectControl = new FormControl('', [nativeValidator as ValidatorFn]);
|
||||
// this.postRedirectControl = new FormControl('', [nativeValidator as ValidatorFn]);
|
||||
break;
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
|
||||
this.oidcAuthMethodType[0].disabled = false;
|
||||
this.oidcAuthMethodType[1].disabled = false;
|
||||
this.oidcAuthMethodType[2].disabled = false;
|
||||
this.authMethodType?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC);
|
||||
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC;
|
||||
|
||||
this.oidcResponseTypes[0].checked = true;
|
||||
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||
this.changeResponseType();
|
||||
|
||||
this.oidcApp.grantTypesList =
|
||||
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
|
||||
|
||||
// this.redirectControl = new FormControl('', [webValidator as ValidatorFn]);
|
||||
// this.postRedirectControl = new FormControl('', [webValidator as ValidatorFn]);
|
||||
break;
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
|
||||
this.oidcResponseTypes[0].checked = true;
|
||||
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||
|
||||
this.oidcApp.grantTypesList =
|
||||
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDCGRANTTYPE_IMPLICIT];
|
||||
|
||||
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||
|
||||
// this.redirectControl = new FormControl('', [webValidator as ValidatorFn]);
|
||||
// this.postRedirectControl = new FormControl('', [webValidator as ValidatorFn]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.oidcApp.name = this.name?.value;
|
||||
this.oidcApp.applicationType = this.applicationType?.value;
|
||||
|
||||
switch (this.applicationType?.value) {
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
|
||||
this.authMethods = [
|
||||
PKCE_METHOD,
|
||||
];
|
||||
|
||||
// automatically set to PKCE and skip step
|
||||
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||
this.oidcApp.grantTypesList = [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
|
||||
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||
|
||||
break;
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
|
||||
this.authMethods = [
|
||||
PKCE_METHOD,
|
||||
CODE_METHOD,
|
||||
POST_METHOD,
|
||||
];
|
||||
|
||||
this.authMethod?.setValue(PKCE_METHOD.key);
|
||||
break;
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
|
||||
this.authMethods = [
|
||||
PKCE_METHOD,
|
||||
IMPLICIT_METHOD,
|
||||
];
|
||||
|
||||
this.authMethod?.setValue(PKCE_METHOD.key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.secondFormGroup = this.fb.group({
|
||||
authMethodType: [OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, [Validators.required]],
|
||||
authMethod: [this.authMethods[0].key, [Validators.required]],
|
||||
});
|
||||
this.secondFormGroup.valueChanges.subscribe(value => {
|
||||
this.oidcApp.authMethodType = value.authMethodType;
|
||||
this.secondFormGroup.valueChanges.subscribe(form => {
|
||||
const partialConfig = getPartialConfigFromAuthMethod(form.authMethod);
|
||||
|
||||
if (partialConfig) {
|
||||
this.oidcApp.responseTypesList = partialConfig.responseTypesList ?? [];
|
||||
this.oidcApp.grantTypesList = partialConfig.grantTypesList ?? [];
|
||||
this.oidcApp.authMethodType = partialConfig.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -173,6 +178,15 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
public changedAppType(type: OIDCApplicationType) {
|
||||
this.firstFormGroup.controls['applicationType'].setValue(type);
|
||||
}
|
||||
|
||||
public changedAppAuthMethod(methodKey: string) {
|
||||
console.log(methodKey);
|
||||
this.secondFormGroup.controls['authMethod'].setValue(methodKey);
|
||||
}
|
||||
|
||||
private async getData({ projectid }: Params): Promise<void> {
|
||||
this.projectId = projectid;
|
||||
this.oidcApp.projectId = projectid;
|
||||
@ -215,66 +229,20 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
public addUri(input: any, target: string): void {
|
||||
const value = input.value.trim();
|
||||
|
||||
if (value !== '') {
|
||||
if (target === 'REDIRECT' && this.redirectControl.valid) {
|
||||
this.oidcApp.redirectUrisList.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
} else if (target === 'POSTREDIRECT' && this.redirectControl.valid) {
|
||||
this.oidcApp.postLogoutRedirectUrisList.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeUri(uri: string, target: string): void {
|
||||
if (target === 'REDIRECT') {
|
||||
const index = this.oidcApp.redirectUrisList.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.oidcApp.redirectUrisList.splice(index, 1);
|
||||
}
|
||||
} else if (target === 'POSTREDIRECT') {
|
||||
const index = this.oidcApp.postLogoutRedirectUrisList.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.oidcApp.postLogoutRedirectUrisList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeResponseType(): void {
|
||||
this.oidcApp.responseTypesList = this.oidcResponseTypes.filter(gt => gt.checked).map(gt => gt.type);
|
||||
}
|
||||
|
||||
moreThanOneOption(options: Array<{ type: OIDCGrantType, checked: boolean, disabled: boolean; }>): boolean {
|
||||
return options.filter(option => option.disabled === false).length > 1;
|
||||
}
|
||||
|
||||
get name(): AbstractControl | null {
|
||||
return this.firstFormGroup.get('name');
|
||||
}
|
||||
|
||||
get applicationType(): AbstractControl | null {
|
||||
return this.firstFormGroup.get('applicationType');
|
||||
}
|
||||
|
||||
public grantTypeChecked(type: OIDCGrantType): boolean {
|
||||
return this.oidcGrantTypes.filter(gt => gt.checked).map(gt => gt.type).findIndex(t => t === type) > -1;
|
||||
}
|
||||
|
||||
get responseTypesList(): AbstractControl | null {
|
||||
return this.secondFormGroup.get('responseTypesList');
|
||||
}
|
||||
|
||||
get authMethodType(): AbstractControl | null {
|
||||
return this.secondFormGroup.get('authMethodType');
|
||||
get authMethod(): AbstractControl | null {
|
||||
return this.secondFormGroup.get('authMethod');
|
||||
}
|
||||
|
||||
// devmode
|
||||
@ -282,24 +250,17 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
get formname(): AbstractControl | null {
|
||||
return this.form.get('name');
|
||||
}
|
||||
|
||||
|
||||
get formresponseTypesList(): AbstractControl | null {
|
||||
return this.form.get('responseTypesList');
|
||||
}
|
||||
|
||||
|
||||
get formgrantTypesList(): AbstractControl | null {
|
||||
return this.form.get('grantTypesList');
|
||||
}
|
||||
|
||||
|
||||
get formapplicationType(): AbstractControl | null {
|
||||
return this.form.get('applicationType');
|
||||
}
|
||||
|
||||
get formauthMethodType(): AbstractControl | null {
|
||||
return this.form.get('authMethodType');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,32 @@
|
||||
<app-meta-layout>
|
||||
<div class="max-width-container">
|
||||
<div class="enlarged-container">
|
||||
<div class="head">
|
||||
<a [routerLink]="['/projects', projectId]" mat-icon-button>
|
||||
<mat-icon class="icon">arrow_back</mat-icon>
|
||||
</a>
|
||||
<h1>{{ 'APP.PAGES.TITLE' | translate }} {{app?.name}}</h1>
|
||||
<div class="title-col">
|
||||
<h1>{{app?.name}}</h1>
|
||||
<span>{{'APP.OIDC.APPTYPE'+app?.oidcConfig?.applicationType | translate}}</span>
|
||||
</div>
|
||||
<ng-container *ngIf="isZitadel === false">
|
||||
<ng-template appHasRole [appHasRole]="['project.app.write:'+projectId, 'project.app.write']">
|
||||
<button *ngIf="!editState" matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button
|
||||
(click)="editState = !editState" aria-label="edit app name">
|
||||
<i class="las la-edit"></i>
|
||||
</button>
|
||||
<button *ngIf="editState" (click)="saveApp()" [disabled]="appNameForm.invalid || name?.disabled"
|
||||
mat-icon-button>
|
||||
<i class="las la-save"></i>
|
||||
</button>
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['project.app.delete:'+projectId, 'project.app.delete']">
|
||||
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn" mat-icon-button
|
||||
(click)="deleteApp()" aria-label="delete app">
|
||||
<i class="las la-trash"></i>
|
||||
</button>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<p class="desc">{{ 'APP.PAGES.DESCRIPTION' | translate }}</p>
|
||||
<p *ngIf="isZitadel" class="zitadel-warning">{{'PROJECT.PAGES.ZITADELPROJECT' | translate}}</p>
|
||||
@ -12,52 +34,85 @@
|
||||
|
||||
<span *ngIf="errorMessage" class="err-container">{{errorMessage}}</span>
|
||||
|
||||
<app-card title="{{ 'APP.PAGES.DETAIL.TITLE' | translate }}" *ngIf="app">
|
||||
<form [formGroup]="appNameForm" (ngSubmit)="saveApp()">
|
||||
<div class="name-content">
|
||||
<mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)">
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_INACTIVE"
|
||||
matTooltip="{{ 'ACTIONS.DEACTIVATE' | translate}}">
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_INACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE"
|
||||
matTooltip="{{ 'ACTIONS.REACTIVATE' | translate}}">
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_ACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
<form *ngIf="app && editState" [formGroup]="appNameForm">
|
||||
<div class="name-content">
|
||||
<mat-button-toggle-group formControlName="state" class="toggle" (change)="changeState($event)">
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_INACTIVE"
|
||||
matTooltip="{{ 'ACTIONS.DEACTIVATE' | translate}}">
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_INACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="AppState.APPSTATE_ACTIVE"
|
||||
matTooltip="{{ 'ACTIONS.REACTIVATE' | translate}}">
|
||||
{{'APP.PAGES.DETAIL.STATE.'+AppState.APPSTATE_ACTIVE | translate}}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
|
||||
<cnsl-form-field class="name-field">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-info-section class="docs-line" *ngIf="docs?.discoveryEndpoint">
|
||||
<p><strong>Discovery Endpoint:</strong> {{docs.discoveryEndpoint}}</p>
|
||||
<p><strong>Issuer:</strong> {{docs.issuer}}</p>
|
||||
</cnsl-info-section>
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
<button type="submit" color="primary" [disabled]="appNameForm.invalid || name?.disabled"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</app-card>
|
||||
|
||||
<app-card title="{{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig">
|
||||
<div card-actions *ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
|
||||
<button [disabled]="!canWrite" mat-stroked-button
|
||||
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
|
||||
<cnsl-form-field class="name-field">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- <cnsl-info-section class="docs-line" *ngIf="docs?.discoveryEndpoint">
|
||||
<p><strong>Discovery Endpoint:</strong> {{docs.discoveryEndpoint}}</p>
|
||||
<p><strong>Issuer:</strong> {{docs.issuer}}</p>
|
||||
</cnsl-info-section> -->
|
||||
|
||||
<div class="compliance"
|
||||
*ngIf="app?.oidcConfig?.complianceProblemsList && app.oidcConfig?.complianceProblemsList?.length">
|
||||
<cnsl-info-section class="problem" type="WARN">
|
||||
<ul style="margin: 0;">
|
||||
<li style="margin: 0 0 .5rem 0;"
|
||||
*ngFor="let problem of app.oidcConfig?.complianceProblemsList || []">
|
||||
{{problem.localizedMessage}}</li>
|
||||
</ul>
|
||||
</cnsl-info-section>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h3 class="full-width section-title">{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}</h3>
|
||||
|
||||
<mat-slide-toggle color="primary" class="devmode" [formControl]="devMode" name="devMode"
|
||||
matTooltip="{{'APP.OIDC.DEVMODEDESC' | translate}}">
|
||||
{{ 'APP.OIDC.DEVMODE' | translate }}
|
||||
</mat-slide-toggle>
|
||||
|
||||
<cnsl-info-section class="step-description"
|
||||
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
|
||||
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</span>
|
||||
</cnsl-info-section>
|
||||
|
||||
<p class="step-description"
|
||||
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<div style="margin: .5rem" class="divider"></div>
|
||||
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="canWrite" [devMode]="devMode?.value"
|
||||
(changedUris)="redirectUrisList = $event" [urisList]="redirectUrisList"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
|
||||
<cnsl-redirect-uris class="redirect-section" [canWrite]="canWrite" [devMode]="devMode?.value"
|
||||
(changedUris)="postLogoutRedirectUrisList = $event" [urisList]="postLogoutRedirectUrisList"
|
||||
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}">
|
||||
</cnsl-redirect-uris>
|
||||
</div>
|
||||
|
||||
<app-auth-method-radio *ngIf="authMethods && initialAuthMethod && app?.oidcConfig" [authMethods]="authMethods"
|
||||
[selected]="initialAuthMethod" [current]="currentAuthMethod"
|
||||
(selectedMethod)="setPartialConfigFromAuthMethod($event)">
|
||||
</app-auth-method-radio>
|
||||
|
||||
<form *ngIf="appForm" [formGroup]="appForm" (ngSubmit)="saveOIDCApp()">
|
||||
<app-card title=" {{ 'APP.OIDC.TITLE' | translate }}" *ngIf="app && app.oidcConfig" [expanded]="false">
|
||||
<div card-actions
|
||||
*ngIf="app?.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE">
|
||||
<button [disabled]="!canWrite" mat-stroked-button
|
||||
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
|
||||
</div>
|
||||
|
||||
<div class="compliance">
|
||||
<cnsl-info-section class="problem">
|
||||
<ul style="margin: 0;">
|
||||
<li style="margin: 0 0 .5rem 0;" *ngFor="let problem of app.oidcConfig.complianceProblemsList">
|
||||
{{problem.localizedMessage}}</li>
|
||||
</ul>
|
||||
</cnsl-info-section>
|
||||
</div>
|
||||
<form *ngIf="appForm" [formGroup]="appForm" (ngSubmit)="saveOIDCApp()">
|
||||
<div class="content">
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'APP.OIDC.CLIENTID' | translate }}</cnsl-label>
|
||||
@ -141,89 +196,46 @@
|
||||
<cnsl-info-section class="full-width desc">
|
||||
<span>{{'APP.OIDC.CLOCKSKEW' | translate}}</span>
|
||||
</cnsl-info-section>
|
||||
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<p class="full-width section-title">{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}</p>
|
||||
|
||||
<mat-slide-toggle color="primary" class="devmode" formControlName="devMode" name="devMode">
|
||||
{{ 'APP.OIDC.DEVMODE' | translate }}
|
||||
</mat-slide-toggle>
|
||||
|
||||
<cnsl-info-section class="step-description">
|
||||
<span style="margin-bottom: 2rem;">{{'APP.OIDC.DEVMODEDESC' | translate}}</span>
|
||||
</cnsl-info-section>
|
||||
|
||||
<cnsl-info-section class="step-description"
|
||||
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
|
||||
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</span>
|
||||
</cnsl-info-section>
|
||||
|
||||
<p class="step-description"
|
||||
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB || applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
|
||||
{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</p>
|
||||
|
||||
<form class="chip-form" (ngSubmit)="add(redInput, RedirectType.REDIRECT)">
|
||||
<cnsl-form-field class="formfield full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.REDIRECT' | translate }}</cnsl-label>
|
||||
|
||||
<input #redInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
|
||||
[formControl]="redirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
|
||||
[disabled]="redirectControl.invalid || !canWrite">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<mat-chip-list class="chiplist formfield full-width" [disabled]="!canWrite" #chipRedirectList>
|
||||
<mat-chip class="chip" *ngFor="let redirect of redirectUrisList" selected
|
||||
[matTooltip]="!redirect?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
[color]="!redirect?.startsWith('https://') ? 'warn': 'green'"
|
||||
(removed)="remove(redirect, RedirectType.REDIRECT)">
|
||||
{{redirect}}
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<p *ngIf="redirectControl.value && redirectControl.invalid" class="error">
|
||||
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
|
||||
<form class="chip-form" (ngSubmit)="add(postInput, RedirectType.POSTREDIRECT)">
|
||||
<cnsl-form-field class="formfield full-width">
|
||||
<cnsl-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</cnsl-label>
|
||||
<input #postInput cnslInput placeholder="{{'APP.OIDC.COMMAORENTERSEPERATION' | translate}}"
|
||||
[formControl]="postRedirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
|
||||
[disabled]="postRedirectControl.invalid || !canWrite">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<mat-chip-list class="chiplist formfield full-width" [disabled]="!canWrite" #chipPostRedirectList>
|
||||
<mat-chip class="chip" *ngFor="let redirect of postLogoutRedirectUrisList" selected
|
||||
(removed)="remove(redirect, RedirectType.POSTREDIRECT)"
|
||||
[matTooltip]="!redirect?.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||
[color]="!redirect?.startsWith('https://') ? 'warn': 'green'">
|
||||
{{redirect}}
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<p *ngIf="postRedirectControl.value && postRedirectControl.invalid" class="error">
|
||||
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
</app-card>
|
||||
|
||||
<button class="submit-button" type="submit" color="primary"
|
||||
[disabled]="appForm.invalid || !canWrite"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
<div class="btn-container">
|
||||
<button class="submit-button" type="submit" color="primary" [disabled]="appForm.invalid || !canWrite"
|
||||
mat-raised-button>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="next-steps">
|
||||
<h5>{{'APP.PAGES.NEXTSTEPS.TITLE' | translate}}</h5>
|
||||
<div class="row">
|
||||
<div class="step">
|
||||
<h6>{{ 'APP.PAGES.NEXTSTEPS.0.TITLE' | translate }}</h6>
|
||||
<p>{{'APP.PAGES.NEXTSTEPS.0.DESC' | translate}}</p>
|
||||
<span class="fill-space"></span>
|
||||
<a [routerLink]="['/projects', this.projectId]" color="primary" mat-mini-fab><i
|
||||
class="las la-angle-right"></i></a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</app-card>
|
||||
<div class="step">
|
||||
<h6>{{ 'APP.PAGES.NEXTSTEPS.1.TITLE' | translate }}</h6>
|
||||
<p>{{'APP.PAGES.NEXTSTEPS.1.DESC' | translate}}</p>
|
||||
<span class="fill-space"></span>
|
||||
<a [routerLink]="['/users', 'create']" color="primary" mat-mini-fab><i
|
||||
class="las la-angle-right"></i></a>
|
||||
</div>
|
||||
<div class="step">
|
||||
<h6>{{ 'APP.PAGES.NEXTSTEPS.2.TITLE' | translate }}</h6>
|
||||
<p>{{'APP.PAGES.NEXTSTEPS.2.DESC' | translate}}</p>
|
||||
<span class="fill-space"></span>
|
||||
<a href="https://docs.zitadel.ch" color="primary" mat-mini-fab><i
|
||||
class="las la-angle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="side" metainfo>
|
||||
<div class="meta-details">
|
||||
<div class="meta-row">
|
||||
|
@ -8,11 +8,21 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.2rem;
|
||||
margin: 0 1rem;
|
||||
.title-col {
|
||||
margin-left: 2rem;
|
||||
font-weight: normal;
|
||||
margin-right: 1rem;
|
||||
min-width: 200px;
|
||||
|
||||
h1 {
|
||||
font-size: 1.2rem;
|
||||
margin: 0 0 0 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
color: var(--grey);
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
@ -20,6 +30,7 @@
|
||||
display: block;
|
||||
font-size: .9rem;
|
||||
color: var(--grey);
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.zitadel-warning {
|
||||
@ -41,10 +52,10 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
.toggle {
|
||||
outline: none;
|
||||
align-self: flex-start;
|
||||
margin-top: 1rem;
|
||||
margin-right: 1rem;
|
||||
border-radius: .5rem;
|
||||
@ -91,6 +102,11 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.redirect-section {
|
||||
flex: 1;
|
||||
margin: 0 .5rem;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
flex: 1 1 30%;
|
||||
margin: 0 .5rem;
|
||||
@ -99,27 +115,9 @@
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.chiplist {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.chip-form {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 1.5rem;
|
||||
margin: 1.5rem 0 0 0;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
@ -142,7 +140,7 @@
|
||||
.desc {
|
||||
color: var(--grey);
|
||||
font-size: 14px;
|
||||
margin-bottom: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.devmode {
|
||||
@ -170,18 +168,67 @@
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.chip[color='green'] {
|
||||
background-color: #56a392 !important;
|
||||
}
|
||||
|
||||
.divider {
|
||||
flex-basis: 100%;
|
||||
margin: 1.5rem .5rem;
|
||||
height: 1px;
|
||||
background-color: rgba(#8795a1, .2);
|
||||
}
|
||||
|
||||
.next-steps {
|
||||
h5 {
|
||||
text-transform: uppercase;
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
|
||||
.step {
|
||||
min-width: 220px;
|
||||
max-width: 280px;
|
||||
padding: 1rem;
|
||||
margin: 0 .5rem;
|
||||
border: 1px solid var(--grey);
|
||||
border-radius: .5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,12 +4,14 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatButtonToggleChange } from '@angular/material/button-toggle';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
import {
|
||||
Application,
|
||||
AppState,
|
||||
@ -27,11 +29,7 @@ import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component';
|
||||
|
||||
enum RedirectType {
|
||||
REDIRECT = 'redirect',
|
||||
POSTREDIRECT = 'postredirect',
|
||||
}
|
||||
import { CODE_METHOD, getAuthMethodFromPartialConfig, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD, CUSTOM_METHOD } from '../authmethods';
|
||||
|
||||
@Component({
|
||||
selector: 'app-app-detail',
|
||||
@ -39,12 +37,20 @@ enum RedirectType {
|
||||
styleUrls: ['./app-detail.component.scss'],
|
||||
})
|
||||
export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
public editState: boolean = false;
|
||||
public currentAuthMethod: string = CUSTOM_METHOD.key;
|
||||
public initialAuthMethod: string = CUSTOM_METHOD.key;
|
||||
public canWrite: boolean = false;
|
||||
public errorMessage: string = '';
|
||||
public removable: boolean = true;
|
||||
public addOnBlur: boolean = true;
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
|
||||
public authMethods: RadioItemAuthType[] = [
|
||||
PKCE_METHOD,
|
||||
CODE_METHOD,
|
||||
POST_METHOD,
|
||||
];
|
||||
private subscription?: Subscription;
|
||||
public projectId: string = '';
|
||||
public app!: Application.AsObject;
|
||||
@ -78,11 +84,10 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
public AppState: any = AppState;
|
||||
public appNameForm!: FormGroup;
|
||||
public appForm!: FormGroup;
|
||||
|
||||
public redirectUrisList: string[] = [];
|
||||
public postLogoutRedirectUrisList: string[] = [];
|
||||
|
||||
public RedirectType: any = RedirectType;
|
||||
|
||||
public isZitadel: boolean = false;
|
||||
public docs!: ZitadelDocs.AsObject;
|
||||
|
||||
@ -90,9 +95,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
public OIDCAuthMethodType: any = OIDCAuthMethodType;
|
||||
public OIDCTokenType: any = OIDCTokenType;
|
||||
|
||||
public redirectControl: FormControl = new FormControl({ value: '', disabled: true });
|
||||
public postRedirectControl: FormControl = new FormControl({ value: '', disabled: true });
|
||||
|
||||
public ChangeType: any = ChangeType;
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
@ -103,6 +105,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
private dialog: MatDialog,
|
||||
private mgmtService: ManagementService,
|
||||
private authService: GrpcAuthService,
|
||||
private router: Router,
|
||||
) {
|
||||
this.appNameForm = this.fb.group({
|
||||
state: [{ value: '', disabled: true }, []],
|
||||
@ -145,12 +148,23 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
this.mgmtService.GetApplicationById(projectid, id).then(app => {
|
||||
this.app = app.toObject();
|
||||
this.appNameForm.patchValue(this.app);
|
||||
console.log(this.app);
|
||||
|
||||
this.getAuthMethodOptions();
|
||||
if (this.app.oidcConfig) {
|
||||
this.initialAuthMethod = this.authMethodFromPartialConfig(this.app.oidcConfig);
|
||||
this.currentAuthMethod = this.initialAuthMethod;
|
||||
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
||||
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
||||
this.authMethods.push(CUSTOM_METHOD);
|
||||
}
|
||||
} else {
|
||||
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
|
||||
}
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
this.appNameForm.enable();
|
||||
this.appForm.enable();
|
||||
this.redirectControl.enable();
|
||||
this.postRedirectControl.enable();
|
||||
}
|
||||
|
||||
if (this.app.oidcConfig?.redirectUrisList) {
|
||||
@ -161,12 +175,22 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
if (this.app.oidcConfig?.clockSkew) {
|
||||
const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000;
|
||||
console.log(inSecs);
|
||||
this.appForm.controls['clockSkewSeconds'].setValue(inSecs);
|
||||
}
|
||||
if (this.app.oidcConfig) {
|
||||
this.appForm.patchValue(this.app.oidcConfig);
|
||||
}
|
||||
|
||||
this.appForm.valueChanges.subscribe(oidcConfig => {
|
||||
this.initialAuthMethod = this.authMethodFromPartialConfig(oidcConfig);
|
||||
if (this.initialAuthMethod === CUSTOM_METHOD.key) {
|
||||
if (!this.authMethods.includes(CUSTOM_METHOD)) {
|
||||
this.authMethods.push(CUSTOM_METHOD);
|
||||
}
|
||||
} else {
|
||||
this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD);
|
||||
}
|
||||
});
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.toast.showError(error);
|
||||
@ -176,6 +200,69 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
this.docs = (await this.mgmtService.GetZitadelDocs()).toObject();
|
||||
}
|
||||
|
||||
private getAuthMethodOptions(): void {
|
||||
switch (this.app.oidcConfig?.applicationType) {
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
|
||||
this.authMethods = [
|
||||
PKCE_METHOD,
|
||||
CUSTOM_METHOD,
|
||||
];
|
||||
break;
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
|
||||
this.authMethods = [
|
||||
PKCE_METHOD,
|
||||
CODE_METHOD,
|
||||
POST_METHOD,
|
||||
];
|
||||
break;
|
||||
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
|
||||
this.authMethods = [
|
||||
PKCE_METHOD,
|
||||
IMPLICIT_METHOD,
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public authMethodFromPartialConfig(config: OIDCConfig.AsObject): string {
|
||||
const key = getAuthMethodFromPartialConfig(config);
|
||||
return key;
|
||||
}
|
||||
|
||||
public setPartialConfigFromAuthMethod(authMethod: string): void {
|
||||
const partialConfig = getPartialConfigFromAuthMethod(authMethod);
|
||||
|
||||
if (partialConfig && this.app.oidcConfig) {
|
||||
this.app.oidcConfig.responseTypesList = partialConfig.responseTypesList ?? [];
|
||||
this.app.oidcConfig.grantTypesList = partialConfig.grantTypesList ?? [];
|
||||
this.app.oidcConfig.authMethodType = partialConfig.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||
this.appForm.patchValue(this.app.oidcConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public deleteApp(): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'APP.PAGES.DIALOG.DELETE.TITLE',
|
||||
descriptionKey: 'APP.PAGES.DIALOG.DELETE.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp && this.projectId && this.app.id) {
|
||||
this.mgmtService.RemoveApplication(this.projectId, this.app.id).then(() => {
|
||||
this.toast.showInfo('APP.TOAST.DELETED', true);
|
||||
|
||||
this.router.navigate(['/projects', this.projectId]);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public changeState(event: MatButtonToggleChange): void {
|
||||
if (event.value === AppState.APPSTATE_ACTIVE) {
|
||||
this.mgmtService.ReactivateApplication(this.projectId, this.app.id).then(() => {
|
||||
@ -192,40 +279,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
public add(input: any, target: RedirectType): void {
|
||||
if (target === RedirectType.POSTREDIRECT && this.postRedirectControl.valid) {
|
||||
if (input.value !== '' && input.value !== ' ' && input.value !== '/') {
|
||||
this.postLogoutRedirectUrisList.push(input.value);
|
||||
}
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
} else if (target === RedirectType.REDIRECT && this.redirectControl.valid) {
|
||||
if (input.value !== '' && input.value !== ' ' && input.value !== '/') {
|
||||
this.redirectUrisList.push(input.value);
|
||||
}
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public remove(redirect: any, target: RedirectType): void {
|
||||
if (target === RedirectType.POSTREDIRECT) {
|
||||
const index = this.postLogoutRedirectUrisList.indexOf(redirect);
|
||||
|
||||
if (index >= 0) {
|
||||
this.postLogoutRedirectUrisList.splice(index, 1);
|
||||
}
|
||||
} else if (target === RedirectType.REDIRECT) {
|
||||
const index = this.redirectUrisList.indexOf(redirect);
|
||||
|
||||
if (index >= 0) {
|
||||
this.redirectUrisList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public saveApp(): void {
|
||||
if (this.appNameForm.valid) {
|
||||
this.app.name = this.name?.value;
|
||||
@ -234,6 +287,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
.UpdateApplication(this.projectId, this.app.id, this.name?.value)
|
||||
.then(() => {
|
||||
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
|
||||
this.editState = false;
|
||||
})
|
||||
.catch(error => {
|
||||
this.toast.showError(error);
|
||||
@ -282,10 +336,12 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
||||
dur.setNanos((Math.floor(this.clockSkewSeconds?.value % 1) * 10000));
|
||||
req.setClockSkew(dur);
|
||||
}
|
||||
console.log(req.toObject());
|
||||
this.mgmtService
|
||||
.UpdateOIDCAppConfig(req)
|
||||
.then(() => {
|
||||
if (this.app.oidcConfig) {
|
||||
this.currentAuthMethod = this.authMethodFromPartialConfig(this.app.oidcConfig);
|
||||
}
|
||||
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -19,6 +19,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { AppRadioModule } from 'src/app/modules/app-radio/app-radio.module';
|
||||
import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
||||
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
|
||||
@ -29,15 +30,20 @@ import { AppCreateComponent } from './app-create/app-create.component';
|
||||
import { AppDetailComponent } from './app-detail/app-detail.component';
|
||||
import { AppSecretDialogComponent } from './app-secret-dialog/app-secret-dialog.component';
|
||||
import { AppsRoutingModule } from './apps-routing.module';
|
||||
import { A11yModule } from '@angular/cdk/a11y';
|
||||
import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppCreateComponent,
|
||||
AppDetailComponent,
|
||||
AppSecretDialogComponent,
|
||||
RedirectUrisComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
A11yModule,
|
||||
AppRadioModule,
|
||||
AppsRoutingModule,
|
||||
FormsModule,
|
||||
TranslateModule,
|
||||
|
166
console/src/app/pages/projects/apps/authmethods.ts
Normal file
166
console/src/app/pages/projects/apps/authmethods.ts
Normal file
@ -0,0 +1,166 @@
|
||||
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
|
||||
import { OIDCAuthMethodType, OIDCConfig, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
|
||||
|
||||
export const CODE_METHOD: RadioItemAuthType = {
|
||||
key: 'CODE',
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CODE.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CODE.DESCRIPTION',
|
||||
disabled: false,
|
||||
prefix: 'CODE',
|
||||
background: 'rgb(89 115 128)',
|
||||
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
|
||||
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
|
||||
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
|
||||
recommended: false,
|
||||
};
|
||||
export const PKCE_METHOD: RadioItemAuthType = {
|
||||
key: 'PKCE',
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.PKCE.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.PKCE.DESCRIPTION',
|
||||
disabled: false,
|
||||
prefix: 'PKCE',
|
||||
background: 'rgb(80 110 92)',
|
||||
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
|
||||
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
|
||||
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
recommended: true,
|
||||
};
|
||||
export const POST_METHOD: RadioItemAuthType = {
|
||||
key: 'POST',
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.POST.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.POST.DESCRIPTION',
|
||||
disabled: false,
|
||||
prefix: 'POST',
|
||||
background: '#595d80',
|
||||
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
|
||||
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
|
||||
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
|
||||
notRecommended: true,
|
||||
};
|
||||
export const PK_JWT_METHOD: RadioItemAuthType = {
|
||||
key: 'PK_JWT',
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.ALTERNATIVE.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.ALTERNATIVE.DESCRIPTION',
|
||||
disabled: false,
|
||||
prefix: 'PK_JWT',
|
||||
background: '#6a506e',
|
||||
responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE,
|
||||
grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE,
|
||||
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
|
||||
};
|
||||
export const IMPLICIT_METHOD: RadioItemAuthType = {
|
||||
key: 'IMPLICIT',
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.IMPLICIT.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.IMPLICIT.DESCRIPTION',
|
||||
disabled: false,
|
||||
prefix: 'IMP',
|
||||
background: 'rgb(144 75 75)',
|
||||
responseType: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN,
|
||||
grantType: OIDCGrantType.OIDCGRANTTYPE_IMPLICIT,
|
||||
authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
notRecommended: true,
|
||||
};
|
||||
export const CUSTOM_METHOD: RadioItemAuthType = {
|
||||
key: 'CUSTOM',
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CUSTOM.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CUSTOM.DESCRIPTION',
|
||||
disabled: false,
|
||||
prefix: 'CUSTOM',
|
||||
background: '#333',
|
||||
};
|
||||
|
||||
export function getPartialConfigFromAuthMethod(authMethod: string): Partial<OIDCConfig.AsObject> | undefined {
|
||||
let config: Partial<OIDCConfig.AsObject>;
|
||||
switch (authMethod) {
|
||||
case CODE_METHOD.key:
|
||||
config = {
|
||||
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
|
||||
};
|
||||
return config;
|
||||
case PKCE_METHOD.key:
|
||||
config = {
|
||||
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
};
|
||||
return config;
|
||||
case POST_METHOD.key:
|
||||
config = {
|
||||
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
|
||||
};
|
||||
return config;
|
||||
// case PK_JWT_METHOD.key:
|
||||
// config = {
|
||||
// responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
// grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
// authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
// };
|
||||
// return config;
|
||||
case IMPLICIT_METHOD.key:
|
||||
config = {
|
||||
responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN],
|
||||
grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_IMPLICIT],
|
||||
authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
};
|
||||
return config;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function getAuthMethodFromPartialConfig(config: Partial<OIDCConfig.AsObject> | OIDCConfig.AsObject): string {
|
||||
const toCheck = [config.responseTypesList, config.grantTypesList, config.authMethodType];
|
||||
const code = JSON.stringify(
|
||||
[
|
||||
[OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
|
||||
]
|
||||
);
|
||||
|
||||
const pkce = JSON.stringify(
|
||||
[
|
||||
[OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
]
|
||||
);
|
||||
|
||||
const post = JSON.stringify(
|
||||
[
|
||||
[OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST,
|
||||
]
|
||||
);
|
||||
|
||||
// const pk_jwt = JSON.stringify(
|
||||
// [
|
||||
// [OIDCResponseType.OIDCRESPONSETYPE_CODE],
|
||||
// [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE],
|
||||
// OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC,
|
||||
// ]
|
||||
// );
|
||||
|
||||
const implicit = JSON.stringify(
|
||||
[
|
||||
[OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN],
|
||||
[OIDCGrantType.OIDCGRANTTYPE_IMPLICIT],
|
||||
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
|
||||
]
|
||||
);
|
||||
|
||||
switch (JSON.stringify(toCheck)) {
|
||||
case code: return CODE_METHOD.key;
|
||||
case pkce: return PKCE_METHOD.key;
|
||||
case post: return POST_METHOD.key;
|
||||
// case pk_jwt: return PK_JWT_METHOD.key;
|
||||
case implicit: return IMPLICIT_METHOD.key;
|
||||
default:
|
||||
return CUSTOM_METHOD.key;
|
||||
}
|
||||
}
|
25
console/src/app/pages/projects/apps/authtypes.ts
Normal file
25
console/src/app/pages/projects/apps/authtypes.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { OIDCApplicationType } from 'src/app/proto/generated/management_pb';
|
||||
|
||||
export const WEB_TYPE = {
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.WEB.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.WEB.DESCRIPTION',
|
||||
type: OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
|
||||
prefix: 'WEB',
|
||||
background: 'rgb(80, 110, 110)',
|
||||
};
|
||||
|
||||
export const USER_AGENT_TYPE = {
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.USERAGENT.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.USERAGENT.DESCRIPTION',
|
||||
type: OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
|
||||
prefix: 'UA',
|
||||
background: '#6a506e',
|
||||
};
|
||||
|
||||
export const NATIVE_TYPE = {
|
||||
titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.NATIVE.TITLE',
|
||||
descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.NATIVE.DESCRIPTION',
|
||||
type: OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE,
|
||||
prefix: 'N',
|
||||
background: '#595d80',
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
<form class="form" (ngSubmit)="add(redInput)">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ title }}</cnsl-label>
|
||||
|
||||
<input #redInput cnslInput placeholder="ex. https://" [formControl]="redirectControl">
|
||||
</cnsl-form-field>
|
||||
<button matTooltip="{{'ACTIONS.ADD' | translate}}" type="submit" mat-icon-button
|
||||
[disabled]="redirectControl.invalid || !canWrite">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="uri-list">
|
||||
<div *ngFor="let uri of urisList" class="uri-line">
|
||||
<span class="uri"
|
||||
[ngClass]="{'green': !devMode && uri?.startsWith('https://'), 'red': !devMode && !uri?.startsWith('https://')}">{{uri}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<i *ngIf="!devMode && !uri?.startsWith('https://')" class="las la-exclamation red"></i>
|
||||
<!-- <i *ngIf="!devMode && uri?.startsWith('https://')" class="las la-check green"></i> -->
|
||||
|
||||
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" mat-icon-button (click)="remove(uri)" class="icon-button">
|
||||
<mat-icon>cancel</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p *ngIf="redirectControl.value && redirectControl.invalid" class="error">
|
||||
{{'APP.OIDC.REDIRECTNOTVALID' | translate}}</p>
|
@ -0,0 +1,61 @@
|
||||
.form {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
min-width: 320px;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-bottom: 14px;
|
||||
margin-right: -0.5rem;
|
||||
}
|
||||
}
|
||||
.uri-list {
|
||||
margin: 0 .5rem;
|
||||
width: 100%;
|
||||
|
||||
.uri-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.uri {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
i.green {
|
||||
font-size: 1rem;
|
||||
line-height: 35px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
i.red {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
mat-icon {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
&:not(:hover) {
|
||||
color: var(--grey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 13px;
|
||||
color: #f44336;
|
||||
margin: 0 .5rem 1.5rem .5rem;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RedirectUrisComponent } from './redirect-uris.component';
|
||||
|
||||
describe('RedirectUrisComponent', () => {
|
||||
let component: RedirectUrisComponent;
|
||||
let fixture: ComponentFixture<RedirectUrisComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ RedirectUrisComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RedirectUrisComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,43 @@
|
||||
import { Component, EventEmitter, Input, OnInit } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-redirect-uris',
|
||||
templateUrl: './redirect-uris.component.html',
|
||||
styleUrls: ['./redirect-uris.component.scss']
|
||||
})
|
||||
export class RedirectUrisComponent implements OnInit {
|
||||
@Input() title: string = '';
|
||||
@Input() devMode: boolean = false;
|
||||
@Input() canWrite: boolean = false;
|
||||
@Input() public urisList: string[] = [];
|
||||
@Input() public redirectControl: FormControl = new FormControl({ value: '', disabled: true });
|
||||
@Input() public changedUris: EventEmitter<string[]> = new EventEmitter();
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.canWrite) {
|
||||
this.redirectControl.enable();
|
||||
}
|
||||
}
|
||||
|
||||
public add(input: any): void {
|
||||
if (this.redirectControl.valid) {
|
||||
if (input.value !== '' && input.value !== ' ' && input.value !== '/') {
|
||||
this.urisList.push(input.value);
|
||||
}
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public remove(redirect: any): void {
|
||||
console.log(redirect);
|
||||
const index = this.urisList.indexOf(redirect);
|
||||
|
||||
if (index >= 0) {
|
||||
this.urisList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,18 +11,27 @@
|
||||
</div>
|
||||
|
||||
<div [routerLink]="['/projects', projectId, 'apps', app.id ]" class="app-wrap"
|
||||
*ngFor="let app of appsSubject | async">
|
||||
<div class="morph-card" matRipple>
|
||||
*ngFor="let app of appsSubject | async"
|
||||
matTooltip="{{'APP.OIDC.APPTYPE'+app.oidcConfig.applicationType | translate}}">
|
||||
<cnsl-app-card class="grid-card" matRipple [type]="app.oidcConfig?.applicationType">
|
||||
{{ app.name.charAt(0)}}
|
||||
</div>
|
||||
<i *ngIf="app.oidcConfig.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE"
|
||||
class="las la-mobile"></i>
|
||||
<i *ngIf="app.oidcConfig.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB"
|
||||
class="las la-code"></i>
|
||||
<i *ngIf="app.oidcConfig.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT"
|
||||
class="las la-code"></i>
|
||||
</cnsl-app-card>
|
||||
<span class="name">{{app.name}}</span>
|
||||
<span class="type">{{'APP.OIDC.APPTYPE'+app.oidcConfig.applicationType | translate}}</span>
|
||||
|
||||
</div>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['project.app.write']">
|
||||
<div class="app-wrap" *ngIf="!disabled" [routerLink]="[ '/projects', projectId, 'apps', 'create']">
|
||||
<div class="morph-card add" matRipple>
|
||||
<cnsl-app-card class="grid-card add" matRipple>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
</cnsl-app-card>
|
||||
<span class="name">{{ 'ACTIONS.NEW' | translate }}</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -1,82 +1,62 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin application-grid-theme($theme) {
|
||||
/* stylelint-disable */
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-dark: mat-color($primary, A900);
|
||||
$accent: map-get($theme, accent);
|
||||
$accent-color: mat-color($primary, 500);
|
||||
/* stylelint-enable */
|
||||
|
||||
.app-grid-header {
|
||||
.app-grid-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-container {
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -1rem;
|
||||
padding-bottom: 2rem;
|
||||
|
||||
.sp-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: calc(82px + 2rem);
|
||||
height: calc(82px + 2rem);
|
||||
}
|
||||
|
||||
.app-wrap {
|
||||
outline: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 150px;
|
||||
|
||||
.morph-card {
|
||||
cursor: pointer;
|
||||
animation: all .2s;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 2rem;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
margin: 1rem;
|
||||
text-transform: uppercase;
|
||||
border-radius: .5rem;
|
||||
border: 2px solid $accent-color;
|
||||
font-weight: 800;
|
||||
background-color: $primary-dark;
|
||||
transition: background-color box-shadow .3s ease-in;
|
||||
background-image:
|
||||
linear-gradient(transparent 11px, rgba($accent-color, .5) 12px, transparent 12px),
|
||||
linear-gradient(90deg, transparent 11px, rgba($accent-color, .5) 12px, transparent 12px);
|
||||
background-size: 100% 12px, 12px 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($accent-color, .1);
|
||||
}
|
||||
|
||||
&.add {
|
||||
background: $accent-color;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba($accent-color, .8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: .8rem;
|
||||
color: #8a868a;
|
||||
}
|
||||
width: calc(82px + 2rem);
|
||||
height: calc(82px + 2rem);
|
||||
}
|
||||
|
||||
.app-wrap {
|
||||
outline: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 150px;
|
||||
|
||||
.grid-card {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 2rem;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
margin: 1rem;
|
||||
text-transform: uppercase;
|
||||
border-radius: .5rem;
|
||||
font-weight: 800;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.add {
|
||||
border: 2px solid var(--grey);
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.type {
|
||||
font-size: 12px;
|
||||
color: #8a868a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { Application } from 'src/app/proto/generated/management_pb';
|
||||
import { Application, OIDCApplicationType, OIDCResponseType } from 'src/app/proto/generated/management_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { NATIVE_TYPE, USER_AGENT_TYPE, WEB_TYPE } from '../../../apps/authtypes';
|
||||
|
||||
@Component({
|
||||
selector: 'app-application-grid',
|
||||
@ -16,6 +17,11 @@ export class ApplicationGridComponent implements OnInit {
|
||||
public appsSubject: BehaviorSubject<Application.AsObject[]> = new BehaviorSubject<Application.AsObject[]>([]);
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public OIDCApplicationType: any = OIDCApplicationType;
|
||||
|
||||
public NATIVE_TYPE: any = NATIVE_TYPE;
|
||||
public WEB_TYPE: any = WEB_TYPE;
|
||||
public USER_AGENT_TYPE: any = USER_AGENT_TYPE;
|
||||
|
||||
constructor(private mgmtService: ManagementService) { }
|
||||
|
||||
|
@ -24,10 +24,17 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.NAME' | translate }} </th>
|
||||
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', role.id ]" mat-cell
|
||||
*matCellDef="let role">
|
||||
{{role.name}} </td>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'APP.NAME' | translate }} </th>
|
||||
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', app.id ]" mat-cell
|
||||
*matCellDef="let app">
|
||||
{{app.name}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'APP.OIDC.APPTYPE' | translate }} </th>
|
||||
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', app.id ]" mat-cell
|
||||
*matCellDef="let app">
|
||||
{{'APP.OIDC.APPTYPE'+app?.oidcConfig?.applicationType | translate}} </td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
|
@ -26,7 +26,7 @@ export class ApplicationsComponent implements AfterViewInit, OnInit {
|
||||
public dataSource!: ProjectApplicationsDataSource;
|
||||
public selection: SelectionModel<Application.AsObject> = new SelectionModel<Application.AsObject>(true, []);
|
||||
|
||||
public displayedColumns: string[] = ['select', 'name'];
|
||||
public displayedColumns: string[] = ['select', 'name', 'type'];
|
||||
|
||||
constructor(private mgmtService: ManagementService, private toast: ToastService) { }
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
<ng-template appHasRole [appHasRole]="['project.write:'+projectId, 'project.write']">
|
||||
<button matTooltip="{{'ACTIONS.EDIT' | translate}}" mat-icon-button (click)="editstate = !editstate"
|
||||
aria-label="Edit project name" *ngIf="isZitadel === false">
|
||||
<mat-icon *ngIf="!editstate">edit</mat-icon>
|
||||
<i *ngIf="!editstate" class="las la-edit"></i>
|
||||
<mat-icon *ngIf="editstate">close</mat-icon>
|
||||
</button>
|
||||
</ng-template>
|
||||
@ -24,11 +24,13 @@
|
||||
<button mat-stroked-button color="warn"
|
||||
[disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false"
|
||||
*ngIf="project?.state === ProjectState.PROJECTSTATE_ACTIVE"
|
||||
(click)="changeState(ProjectState.PROJECTSTATE_INACTIVE)">{{'PROJECT.TABLE.DEACTIVATE' | translate}}</button>
|
||||
(click)="changeState(ProjectState.PROJECTSTATE_INACTIVE)">{{'PROJECT.TABLE.DEACTIVATE' |
|
||||
translate}}</button>
|
||||
<button mat-stroked-button color="warn"
|
||||
[disabled]="isZitadel || (['project.write$', 'project.write:'+ project.projectId]| hasRole | async) == false"
|
||||
*ngIf="project?.state === ProjectState.PROJECTSTATE_INACTIVE"
|
||||
(click)="changeState(ProjectState.PROJECTSTATE_ACTIVE)">{{'PROJECT.TABLE.ACTIVATE' | translate}}</button>
|
||||
(click)="changeState(ProjectState.PROJECTSTATE_ACTIVE)">{{'PROJECT.TABLE.ACTIVATE' |
|
||||
translate}}</button>
|
||||
|
||||
<div class="full-width">
|
||||
<div class="line">
|
||||
@ -78,7 +80,7 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['project.role.read:' + project.projectId, 'project.role.read']">
|
||||
<app-card title="{{ 'PROJECT.ROLE.TITLE' | translate }}"
|
||||
<app-card id="roles" title="{{ 'PROJECT.ROLE.TITLE' | translate }}"
|
||||
description="{{ 'PROJECT.ROLE.DESCRIPTION' | translate }}">
|
||||
<p>{{'PROJECT.ROLE.OPTIONS' | translate}}</p>
|
||||
<mat-checkbox [(ngModel)]="project.projectRoleAssertion" (change)="saveProject()"
|
||||
@ -118,7 +120,8 @@
|
||||
<div class="meta-row">
|
||||
<span class="first">{{'PROJECT.STATE.TITLE' | translate}}:</span>
|
||||
<span *ngIf="project && project.state !== undefined" class="state"
|
||||
[ngClass]="{'active': project.state === ProjectState.PROJECTSTATE_ACTIVE, 'inactive': project.state === ProjectState.PROJECTSTATE_INACTIVE}">{{'PROJECT.STATE.'+project.state | translate}}</span>
|
||||
[ngClass]="{'active': project.state === ProjectState.PROJECTSTATE_ACTIVE, 'inactive': project.state === ProjectState.PROJECTSTATE_INACTIVE}">{{'PROJECT.STATE.'+project.state
|
||||
| translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -14,6 +14,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { MemberCreateDialogModule } from 'src/app/modules/add-member-dialog/member-create-dialog.module';
|
||||
import { AppCardModule } from 'src/app/modules/app-card/app-card.module';
|
||||
import { CardModule } from 'src/app/modules/card/card.module';
|
||||
import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
||||
import { ContributorsModule } from 'src/app/modules/contributors/contributors.module';
|
||||
@ -43,6 +44,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
AppCardModule,
|
||||
OwnedProjectDetailRoutingModule,
|
||||
TranslateModule,
|
||||
ReactiveFormsModule,
|
||||
|
@ -1362,4 +1362,11 @@ export class ManagementService {
|
||||
public UpdateOIDCAppConfig(req: OIDCConfigUpdate): Promise<OIDCConfig> {
|
||||
return this.grpcService.mgmt.updateApplicationOIDCConfig(req);
|
||||
}
|
||||
|
||||
public RemoveApplication(projectId: string, appId: string): Promise<Empty> {
|
||||
const req = new ApplicationID();
|
||||
req.setId(appId);
|
||||
req.setProjectId(projectId);
|
||||
return this.grpcService.mgmt.removeApplication(req);
|
||||
}
|
||||
}
|
||||
|
@ -961,12 +961,34 @@
|
||||
"1": "Aktiv",
|
||||
"2": "Inaktiv"
|
||||
}
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE": {
|
||||
"TITLE": "App löschen",
|
||||
"DESCRIPTION":"Wollen Sie diese App wirklich löschen?"
|
||||
}
|
||||
},
|
||||
"NEXTSTEPS": {
|
||||
"TITLE":"Nächste Schritte",
|
||||
"0": {
|
||||
"TITLE":"Rollen festlegen",
|
||||
"DESC":"Erfassen Sie Rollen für ihr Projekt"
|
||||
},
|
||||
"1": {
|
||||
"TITLE":"Benutzer hinzufügen",
|
||||
"DESC":"Fügen Sie Nutzer ihrer Organisation hinzu"
|
||||
},
|
||||
"2": {
|
||||
"TITLE":"Hilfe & Support",
|
||||
"DESC":"Lesen Sie unsere Dokumentation zum Erstellen von Applikation oder kontaktieren Sie unseren Support"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NAME": "Name",
|
||||
"TYPE":"Anwendungstyp",
|
||||
"GRANT":"Berechtigungstypen",
|
||||
"OIDC": {
|
||||
"CURRENT":"Aktuelle Konfiguration",
|
||||
"TOKENSECTIONTITLE":"AuthToken Optionen",
|
||||
"REDIRECTSECTIONTITLE":"Weiterleitungseinstellungen",
|
||||
"PROSWITCH":"Konfigurator überspringen",
|
||||
@ -1022,13 +1044,58 @@
|
||||
"IDTOKENROLEASSERTION_DESCRIPTION":"Bei Auswahl werden dem Id Token die Rollen des Authentifizierten Benutzers hinzugefügt.",
|
||||
"IDTOKENUSERINFOASSERTION":"User Info im ID Token",
|
||||
"IDTOKENUSERINFOASSERTION_DESCRIPTION":"Ermöglich OIDC clients claims von profile, email, phone und address direkt vom ID Token zu beziehen.",
|
||||
"CLOCKSKEW":"ermöglicht Clients, den Taktversatz von OP und Client zu verarbeiten. Die Dauer (0-5s) wird der exp addiert und von iats, auth_time und nbf abgezogen."
|
||||
"CLOCKSKEW":"ermöglicht Clients, den Taktversatz von OP und Client zu verarbeiten. Die Dauer (0-5s) wird der exp addiert und von iats, auth_time und nbf abgezogen.",
|
||||
"RECOMMENDED":"Empfohlen",
|
||||
"NOTRECOMMENDED":"nicht empfohlen",
|
||||
"SELECTION":{
|
||||
"APPTYPE": {
|
||||
"WEB": {
|
||||
"TITLE":"Web",
|
||||
"DESCRIPTION":"Standard Web applications wie .net, PHP, Node.js, Java, etc."
|
||||
},
|
||||
"NATIVE": {
|
||||
"TITLE":"NATIVE",
|
||||
"DESCRIPTION":"Mobile Apps, Desktop, Smart Devices, etc."
|
||||
},
|
||||
"USERAGENT": {
|
||||
"TITLE":"User Agent",
|
||||
"DESCRIPTION":"Single Page Applications (SPA) und grundsätzlich alle im Browser aufgeführten JS Frameworks"
|
||||
}
|
||||
},
|
||||
"AUTHMETHOD": {
|
||||
"CODE": {
|
||||
"TITLE":"Code",
|
||||
"DESCRIPTION":"Tausche den Authorization Code gegen Tokens ein"
|
||||
},
|
||||
"PKCE": {
|
||||
"TITLE":"PKCE",
|
||||
"DESCRIPTION":"Nutze einen Zufalls Hash Wert anstelle des Client Secret für mehr Sicherheit"
|
||||
},
|
||||
"POST": {
|
||||
"TITLE":"POST",
|
||||
"DESCRIPTION":"Sende client_id und client_secret im (HTML) Formular"
|
||||
},
|
||||
"PK_JWT": {
|
||||
"TITLE":"Private Key JWT",
|
||||
"DESCRIPTION":"Nutze einen Private Key um deine Application zu authentifizieren"
|
||||
},
|
||||
"IMPLICIT": {
|
||||
"TITLE":"Implicit",
|
||||
"DESCRIPTION":"Erhalte die Token direkt vom authorize Endpoint"
|
||||
},
|
||||
"CUSTOM": {
|
||||
"TITLE":"Custom",
|
||||
"DESCRIPTION":"Deine Konfiguration entspricht keiner anderen Option."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"TOAST": {
|
||||
"REACTIVATED":"Anwendung reaktiviert.",
|
||||
"DEACTIVATED":"Anwendung deaktiviert.",
|
||||
"OIDCUPDATED":"OIDC-Konfiguration geändert.",
|
||||
"OIDCCLIENTSECRETREGENERATED":"OIDC-Client Secret generiert."
|
||||
"OIDCCLIENTSECRETREGENERATED":"OIDC-Client Secret generiert.",
|
||||
"DELETED":"App gelöscht."
|
||||
}
|
||||
},
|
||||
"GENDERS": {
|
||||
|
@ -961,12 +961,34 @@
|
||||
"1": "Active",
|
||||
"2": "Inactive"
|
||||
}
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE": {
|
||||
"TITLE": "Delete App",
|
||||
"DESCRIPTION":"Do you really want to delete this application?"
|
||||
}
|
||||
},
|
||||
"NEXTSTEPS": {
|
||||
"TITLE":"Next Steps",
|
||||
"0": {
|
||||
"TITLE":"Add roles",
|
||||
"DESC":"Enter your project roles"
|
||||
},
|
||||
"1": {
|
||||
"TITLE":"Add users",
|
||||
"DESC":"Add new users of your organization"
|
||||
},
|
||||
"2": {
|
||||
"TITLE":"Help & Support",
|
||||
"DESC":"Read our documentation on creating applications or contact our support"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NAME": "Name",
|
||||
"TYPE":"Application Type",
|
||||
"GRANT":"Grant Types",
|
||||
"OIDC": {
|
||||
"CURRENT":"Current Config",
|
||||
"TOKENSECTIONTITLE":"AuthToken Options",
|
||||
"REDIRECTSECTIONTITLE":"Redirect Settings",
|
||||
"PROSWITCH":"I'm a pro. Skip this wizard.",
|
||||
@ -1022,13 +1044,58 @@
|
||||
"IDTOKENROLEASSERTION_DESCRIPTION":"If selected, the roles of the authenticated user are added to the ID token.",
|
||||
"IDTOKENUSERINFOASSERTION":"User Info inside ID Token",
|
||||
"IDTOKENUSERINFOASSERTION_DESCRIPTION":"Enables clients to retrieve profile, email, phone and address claims from ID token.",
|
||||
"CLOCKSKEW":"Enables clients to handle clock skew of OP and client. The duration (0-5s) will be added to exp claim and subtracted from iats, auth_time and nbf."
|
||||
"CLOCKSKEW":"Enables clients to handle clock skew of OP and client. The duration (0-5s) will be added to exp claim and subtracted from iats, auth_time and nbf.",
|
||||
"RECOMMENDED":"recommended",
|
||||
"NOTRECOMMENDED":"not recommended",
|
||||
"SELECTION":{
|
||||
"APPTYPE": {
|
||||
"WEB": {
|
||||
"TITLE":"Web",
|
||||
"DESCRIPTION":"Regular Web applications like .net, PHP, Node.js, Java, etc."
|
||||
},
|
||||
"NATIVE": {
|
||||
"TITLE":"NATIVE",
|
||||
"DESCRIPTION":"Mobile Apps, Desktop, Smart Devices, etc."
|
||||
},
|
||||
"USERAGENT": {
|
||||
"TITLE":"User Agent",
|
||||
"DESCRIPTION":"Single Page Applications (SPA) and in general all JS frameworks executed in browsers"
|
||||
}
|
||||
},
|
||||
"AUTHMETHOD": {
|
||||
"CODE": {
|
||||
"TITLE":"Code",
|
||||
"DESCRIPTION":"Exchange the authorization code for the tokens"
|
||||
},
|
||||
"PKCE": {
|
||||
"TITLE":"PKCE",
|
||||
"DESCRIPTION":"Use a random hash instead of a static client secret for more security"
|
||||
},
|
||||
"POST": {
|
||||
"TITLE":"POST",
|
||||
"DESCRIPTION":"Send client_id and client_secret as part of the form"
|
||||
},
|
||||
"PK_JWT": {
|
||||
"TITLE":"Private Key JWT",
|
||||
"DESCRIPTION":"Use a private key to authorize your application"
|
||||
},
|
||||
"IMPLICIT": {
|
||||
"TITLE":"Implicit",
|
||||
"DESCRIPTION":"Get the tokens directly from the authorization endpoint"
|
||||
},
|
||||
"CUSTOM": {
|
||||
"TITLE":"Custom",
|
||||
"DESCRIPTION":"Your setting doesn't correspond to any other option."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"TOAST": {
|
||||
"REACTIVATED":"Application reactivated.",
|
||||
"DEACTIVATED":"Application deactivated.",
|
||||
"OIDCUPDATED":"OIDC configuration updated.",
|
||||
"OIDCCLIENTSECRETREGENERATED":"OIDC client secret generated."
|
||||
"OIDCCLIENTSECRETREGENERATED":"OIDC client secret generated.",
|
||||
"DELETED":"App deleted."
|
||||
}
|
||||
},
|
||||
"GENDERS": {
|
||||
|
@ -5,10 +5,12 @@
|
||||
@import './styles/link.scss';
|
||||
@import './styles/sidenav-list';
|
||||
@import 'src/app/modules/avatar/avatar.component';
|
||||
@import 'src/app/modules/app-radio/app-type-radio/app-type-radio.component';
|
||||
@import 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
|
||||
@import 'src/app/modules/changes/changes.component';
|
||||
@import 'src/app/modules/info-section/info-section.component';
|
||||
@import 'src/app/modules/detail-layout/detail-layout.component';
|
||||
@import 'src/app/pages/projects/owned-projects/owned-project-detail/application-grid/application-grid.component';
|
||||
@import 'src/app/modules/app-card/app-card.component';
|
||||
@import 'src/app/pages/users/user-detail/auth-user-detail/theme-setting/theme-card';
|
||||
@import 'src/app/pages/users/user-detail/memberships/memberships.component';
|
||||
@import 'src/app/app.component.scss';
|
||||
@ -19,11 +21,13 @@
|
||||
|
||||
@mixin component-themes($theme) {
|
||||
@include avatar-theme($theme);
|
||||
@include app-type-radio-theme($theme);
|
||||
@include app-auth-method-radio-theme($theme);
|
||||
@include card-theme($theme);
|
||||
@include table-theme($theme);
|
||||
@include detail-layout-theme($theme);
|
||||
@include sidenav-list-theme($theme);
|
||||
@include application-grid-theme($theme);
|
||||
@include app-card-theme($theme);
|
||||
@include membership-theme($theme);
|
||||
@include changes-theme($theme);
|
||||
@include theme-card($theme);
|
||||
|
@ -64,7 +64,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mat-checkbox {
|
||||
td .mat-checkbox,
|
||||
th .mat-checkbox {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user