fix(console-v2): app detail layout, create layout stepper (#3680)

* app detail

* app-detail layout

* app layout, create layout component, cleanup

* lint
This commit is contained in:
Max Peintner
2022-05-23 08:43:03 +02:00
committed by GitHub
parent 32ccada7a9
commit 6ec3c56883
56 changed files with 1897 additions and 1906 deletions
@@ -1,133 +1,313 @@
<div class="max-width-container">
<div class="enlarged-container">
<div class="abort-container">
<button (click)="close()" mat-icon-button>
<mat-icon>close</mat-icon>
</button>
<span class="abort">{{ 'APP.PAGES.CREATE_OIDC' | translate }}</span
><span class="abort-2">Step {{ currentCreateStep }} of {{ createSteps }}</span>
</div>
<cnsl-create-layout
title="{{ 'APP.PAGES.CREATE_OIDC' | translate }}"
[createSteps]="createSteps"
[currentCreateStep]="currentCreateStep"
(closed)="close()"
>
<h1>{{ 'APP.PAGES.CREATE_OIDC_DESC_TITLE' | translate }}</h1>
<mat-progress-bar class="progress-bar" color="primary" *ngIf="loading" mode="indeterminate"></mat-progress-bar>
<div class="app-create-content">
<h1>{{ 'APP.PAGES.CREATE_OIDC_DESC_TITLE' | translate }}</h1>
<mat-progress-bar class="progress-bar" color="primary" *ngIf="loading" mode="indeterminate"></mat-progress-bar>
<mat-checkbox class="proswitch" color="primary" [(ngModel)]="devmode">
{{ 'APP.OIDC.PROSWITCH' | translate }}
</mat-checkbox>
<mat-checkbox class="proswitch" color="primary" [(ngModel)]="devmode">
{{ 'APP.OIDC.PROSWITCH' | translate }}
</mat-checkbox>
<mat-horizontal-stepper
class="stepper"
*ngIf="!devmode"
linear
#stepper
labelPosition="bottom"
(selectionChange)="changeStep($event)"
>
<mat-step [stepControl]="firstFormGroup" [editable]="true">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>{{ 'APP.OIDC.NAMEANDTYPESECTION' | translate }}</ng-template>
<mat-horizontal-stepper
class="stepper"
*ngIf="!devmode"
linear
#stepper
labelPosition="bottom"
(selectionChange)="changeStep($event)"
>
<mat-step [stepControl]="firstFormGroup" [editable]="true">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>{{ 'APP.OIDC.NAMEANDTYPESECTION' | translate }}</ng-template>
<p class="step-title">{{ 'APP.OIDC.TITLEFIRST' | translate }}</p>
<cnsl-form-field appearance="outline" class="name-formfield">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput cdkFocusInitial formControlName="name" />
<span cnslError *ngIf="name?.errors?.required">{{ 'PROJECT.APP.NAMEREQUIRED' | translate }}</span>
</cnsl-form-field>
<p class="step-title">{{ 'APP.OIDC.TITLEFIRST' | translate }}</p>
<cnsl-form-field appearance="outline" class="name-formfield">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput cdkFocusInitial formControlName="name" />
<span cnslError *ngIf="name?.errors?.required">{{ 'PROJECT.APP.NAMEREQUIRED' | translate }}</span>
</cnsl-form-field>
<p class="step-title">{{ 'APP.OIDC.TYPETITLE' | translate }}</p>
<p class="step-title">{{ 'APP.OIDC.TYPETITLE' | translate }}</p>
<cnsl-type-radio [types]="appTypes" (selectedType)="appType?.setValue($event)" [selected]="appType?.value">
</cnsl-type-radio>
<div class="app-create-actions">
<button
mat-raised-button
[disabled]="firstFormGroup.invalid"
color="primary"
matStepperNext
[attr.data-e2e]="'continue-button-nameandtype'"
>
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
</mat-step>
<!-- skip for native applications -->
<mat-step
*ngIf="oidcAppRequest.appType !== OIDCAppType.OIDC_APP_TYPE_NATIVE"
[stepControl]="secondFormGroup"
[editable]="true"
>
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>{{ 'APP.AUTHMETHODSECTION' | translate }}</ng-template>
<cnsl-auth-method-radio
[authMethods]="authMethods"
[selected]="authMethod?.value"
[isOIDC]="appType?.value?.createType === AppCreateType.OIDC"
(selectedMethod)="authMethod?.setValue($event)"
>
</cnsl-auth-method-radio>
<div class="app-create-actions">
<button class="bck-button" mat-stroked-button matStepperPrevious>{{ 'ACTIONS.BACK' | translate }}</button>
<button
mat-raised-button
color="primary"
[disabled]="secondFormGroup.invalid"
matStepperNext
[attr.data-e2e]="'continue-button-authmethod'"
>
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
</mat-step>
<!-- show redirect step only for OIDC apps -->
<mat-step *ngIf="appType?.value?.createType === AppCreateType.OIDC" [editable]="true">
<ng-template matStepLabel>{{ 'APP.OIDC.REDIRECTSECTION' | translate }}</ng-template>
<p class="step-title">{{ 'APP.OIDC.REDIRECTTITLE' | translate }}</p>
<p
class="step-description cnsl-secondary-text"
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
<cnsl-type-radio [types]="appTypes" (selectedType)="appType?.setValue($event)" [selected]="appType?.value">
</cnsl-type-radio>
<div class="app-create-actions">
<button
mat-raised-button
[disabled]="firstFormGroup.invalid"
color="primary"
matStepperNext
[attr.data-e2e]="'continue-button-nameandtype'"
>
{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}
</p>
<p class="step-description cnsl-secondary-text" *ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB">
{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}
</p>
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
</mat-step>
<!-- skip for native applications -->
<mat-step
*ngIf="oidcAppRequest.appType !== OIDCAppType.OIDC_APP_TYPE_NATIVE"
[stepControl]="secondFormGroup"
[editable]="true"
>
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>{{ 'APP.AUTHMETHODSECTION' | translate }}</ng-template>
<cnsl-auth-method-radio
[authMethods]="authMethods"
[selected]="authMethod?.value"
[isOIDC]="appType?.value?.createType === AppCreateType.OIDC"
(selectedMethod)="authMethod?.setValue($event)"
>
</cnsl-auth-method-radio>
<div class="app-create-actions">
<button class="bck-button" mat-stroked-button matStepperPrevious>{{ 'ACTIONS.BACK' | translate }}</button>
<button
mat-raised-button
color="primary"
[disabled]="secondFormGroup.invalid"
matStepperNext
[attr.data-e2e]="'continue-button-authmethod'"
>
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</form>
</mat-step>
<!-- show redirect step only for OIDC apps -->
<mat-step *ngIf="appType?.value?.createType === AppCreateType.OIDC" [editable]="true">
<ng-template matStepLabel>{{ 'APP.OIDC.REDIRECTSECTION' | translate }}</ng-template>
<p class="step-title">{{ 'APP.OIDC.REDIRECTTITLE' | translate }}</p>
<p class="step-description cnsl-secondary-text" *ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}
</p>
<p class="step-description cnsl-secondary-text" *ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB">
{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}
</p>
<cnsl-redirect-uris
class="redirect-section"
[canWrite]="true"
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)"
[urisList]="oidcAppRequest.redirectUrisList"
[getValues]="requestRedirectValuesSubject$"
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
>
</cnsl-redirect-uris>
<p class="step-title">{{ 'APP.OIDC.POSTREDIRECTTITLE' | translate }}</p>
<p class="step-description cnsl-secondary-text" *ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE">
{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}
</p>
<p
class="step-description cnsl-secondary-text"
*ngIf="
oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB ||
oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_USER_AGENT
"
>
{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}
</p>
<cnsl-redirect-uris
class="redirect-section"
[canWrite]="true"
(changedUris)="oidcAppRequest.postLogoutRedirectUrisList = $any($event)"
[urisList]="oidcAppRequest.postLogoutRedirectUrisList"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
[getValues]="requestRedirectValuesSubject$"
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
<div class="app-create-actions">
<button mat-stroked-button class="bck-button" matStepperPrevious>{{ 'ACTIONS.BACK' | translate }}</button>
<button mat-raised-button color="primary" matStepperNext [attr.data-e2e]="'continue-button-redirecturis'">
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</mat-step>
<mat-step>
<ng-template matStepLabel>{{ 'APP.OIDC.OVERVIEWSECTION' | translate }}</ng-template>
<p class="step-title">{{ 'APP.OIDC.OVERVIEWTITLE' | translate }}</p>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.NAME' | translate }}
</span>
<span class="right">
{{ oidcAppRequest.name }}
</span>
</div>
<ng-container *ngIf="appType?.value?.createType === AppCreateType.OIDC">
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.TYPE' | translate }}
</span>
<span class="right">
{{ 'APP.OIDC.APPTYPE.' + oidcAppRequest.appType | translate }}
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.GRANT' | translate }}
</span>
<span class="right" *ngIf="oidcAppRequest.grantTypesList && oidcAppRequest.grantTypesList.length > 0">
[<span *ngFor="let element of oidcAppRequest.grantTypesList; index as i">
{{ 'APP.OIDC.GRANT.' + element | translate }}
{{ i < oidcAppRequest.grantTypesList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.OIDC.RESPONSETYPE' | translate }}
</span>
<span class="right" *ngIf="oidcAppRequest.responseTypesList && oidcAppRequest.responseTypesList.length > 0">
[<span *ngFor="let element of oidcAppRequest.responseTypesList; index as i">
{{ 'APP.OIDC.RESPONSE.' + element | translate }}
{{ i < oidcAppRequest.responseTypesList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.AUTHMETHOD' | translate }}
</span>
<span class="right">
<span>
{{ 'APP.OIDC.AUTHMETHOD.' + oidcAppRequest?.authMethodType | translate }}
</span>
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.OIDC.REDIRECT' | translate }}
</span>
<span class="right" *ngIf="oidcAppRequest.redirectUrisList && oidcAppRequest.redirectUrisList.length > 0">
[<span *ngFor="let redirect of oidcAppRequest.redirectUrisList; index as i">
{{ redirect }}
{{ i < oidcAppRequest.redirectUrisList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
</span>
<span
class="right"
*ngIf="oidcAppRequest.postLogoutRedirectUrisList && oidcAppRequest.postLogoutRedirectUrisList.length > 0"
>
[<span *ngFor="let redirect of oidcAppRequest.postLogoutRedirectUrisList; index as i">
{{ redirect }}
{{ i < oidcAppRequest.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
</ng-container>
<ng-container *ngIf="appType?.value?.createType === AppCreateType.API">
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.AUTHMETHOD' | translate }}
</span>
<span class="right">
<span>
{{ 'APP.API.AUTHMETHOD.' + apiAppRequest?.authMethodType | translate }}
</span>
</span>
</div>
</ng-container>
<div class="app-create-actions">
<button mat-stroked-button matStepperPrevious class="bck-button">{{ 'ACTIONS.BACK' | translate }}</button>
<button
mat-raised-button
class="create-button"
color="primary"
(click)="createApp()"
[attr.data-e2e]="'create-button'"
>
{{ 'ACTIONS.CREATE' | translate }}
</button>
</div>
</mat-step>
</mat-horizontal-stepper>
<div *ngIf="devmode" class="dev">
<form [formGroup]="form" (ngSubmit)="createApp()" [attr.data-e2e]="'create-app-wizzard-3'">
<div class="content">
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" />
</cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.TYPE' | translate }}</cnsl-label>
<mat-select formControlName="appType">
<mat-option *ngFor="let appType of appTypes" [value]="appType">
{{ appType.titleI18nKey | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<ng-container *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.OIDC.GRANTTYPE' | translate }}</cnsl-label>
<mat-select formControlName="grantTypesList" multiple>
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant.type">
{{ 'APP.OIDC.GRANT.' + grant.type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</cnsl-label>
<mat-select formControlName="responseTypesList" multiple>
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type.type">
{{ 'APP.OIDC.RESPONSE.' + type.type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
</ng-container>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.AUTHMETHOD' | translate }}</cnsl-label>
<mat-select formControlName="authMethodType">
<mat-option *ngFor="let type of authMethodTypes" [value]="type.type">
<span *ngIf="type.oidc">{{ 'APP.OIDC.AUTHMETHOD.' + type.type | translate }}</span>
<span *ngIf="type.api">{{ 'APP.API.AUTHMETHOD.' + type.type | translate }}</span>
</mat-option>
</mat-select>
</cnsl-form-field>
</div>
<div class="content" *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
<div class="formfield full-width">
<cnsl-redirect-uris
class="redirect-section"
[canWrite]="true"
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)"
[urisList]="oidcAppRequest.redirectUrisList"
[getValues]="requestRedirectValuesSubject$"
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
[getValues]="requestRedirectValuesSubject$"
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
<p class="step-title">{{ 'APP.OIDC.POSTREDIRECTTITLE' | translate }}</p>
<p
class="step-description cnsl-secondary-text"
*ngIf="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}
</p>
<p
class="step-description cnsl-secondary-text"
*ngIf="
oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_WEB ||
oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_USER_AGENT
"
>
{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}
</p>
<cnsl-redirect-uris
class="redirect-section"
[canWrite]="true"
@@ -138,212 +318,19 @@
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
<div class="app-create-actions">
<button mat-stroked-button class="bck-button" matStepperPrevious>{{ 'ACTIONS.BACK' | translate }}</button>
<button mat-raised-button color="primary" matStepperNext [attr.data-e2e]="'continue-button-redirecturis'">
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</mat-step>
<mat-step>
<ng-template matStepLabel>{{ 'APP.OIDC.OVERVIEWSECTION' | translate }}</ng-template>
<p class="step-title">{{ 'APP.OIDC.OVERVIEWTITLE' | translate }}</p>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.NAME' | translate }}
</span>
<span class="right">
{{ oidcAppRequest.name }}
</span>
</div>
<ng-container *ngIf="appType?.value?.createType === AppCreateType.OIDC">
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.TYPE' | translate }}
</span>
<span class="right">
{{ 'APP.OIDC.APPTYPE.' + oidcAppRequest.appType | translate }}
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.GRANT' | translate }}
</span>
<span class="right" *ngIf="oidcAppRequest.grantTypesList && oidcAppRequest.grantTypesList.length > 0">
[<span *ngFor="let element of oidcAppRequest.grantTypesList; index as i">
{{ 'APP.OIDC.GRANT.' + element | translate }}
{{ i < oidcAppRequest.grantTypesList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.OIDC.RESPONSETYPE' | translate }}
</span>
<span class="right" *ngIf="oidcAppRequest.responseTypesList && oidcAppRequest.responseTypesList.length > 0">
[<span *ngFor="let element of oidcAppRequest.responseTypesList; index as i">
{{ 'APP.OIDC.RESPONSE.' + element | translate }}
{{ i < oidcAppRequest.responseTypesList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.AUTHMETHOD' | translate }}
</span>
<span class="right">
<span>
{{ 'APP.OIDC.AUTHMETHOD.' + oidcAppRequest?.authMethodType | translate }}
</span>
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.OIDC.REDIRECT' | translate }}
</span>
<span class="right" *ngIf="oidcAppRequest.redirectUrisList && oidcAppRequest.redirectUrisList.length > 0">
[<span *ngFor="let redirect of oidcAppRequest.redirectUrisList; index as i">
{{ redirect }}
{{ i < oidcAppRequest.redirectUrisList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
</span>
<span
class="right"
*ngIf="oidcAppRequest.postLogoutRedirectUrisList && oidcAppRequest.postLogoutRedirectUrisList.length > 0"
>
[<span *ngFor="let redirect of oidcAppRequest.postLogoutRedirectUrisList; index as i">
{{ redirect }}
{{ i < oidcAppRequest.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} </span
>]
</span>
</div>
</ng-container>
<ng-container *ngIf="appType?.value?.createType === AppCreateType.API">
<div class="row cnsl-secondary-text">
<span class="left">
{{ 'APP.AUTHMETHOD' | translate }}
</span>
<span class="right">
<span>
{{ 'APP.API.AUTHMETHOD.' + apiAppRequest?.authMethodType | translate }}
</span>
</span>
</div>
</ng-container>
<div class="app-create-actions">
<button mat-stroked-button matStepperPrevious class="bck-button">{{ 'ACTIONS.BACK' | translate }}</button>
<button
mat-raised-button
class="create-button"
color="primary"
(click)="createApp()"
[attr.data-e2e]="'create-button'"
>
{{ 'ACTIONS.CREATE' | translate }}
</button>
</div>
</mat-step>
</mat-horizontal-stepper>
<div *ngIf="devmode" class="dev">
<form [formGroup]="form" (ngSubmit)="createApp()" [attr.data-e2e]="'create-app-wizzard-3'">
<div class="content">
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
<input cnslInput formControlName="name" />
</cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.TYPE' | translate }}</cnsl-label>
<mat-select formControlName="appType">
<mat-option *ngFor="let appType of appTypes" [value]="appType">
{{ appType.titleI18nKey | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<ng-container *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.OIDC.GRANTTYPE' | translate }}</cnsl-label>
<mat-select formControlName="grantTypesList" multiple>
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant.type">
{{ 'APP.OIDC.GRANT.' + grant.type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</cnsl-label>
<mat-select formControlName="responseTypesList" multiple>
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type.type">
{{ 'APP.OIDC.RESPONSE.' + type.type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
</ng-container>
<cnsl-form-field appearance="outline" class="formfield">
<cnsl-label>{{ 'APP.AUTHMETHOD' | translate }}</cnsl-label>
<mat-select formControlName="authMethodType">
<mat-option *ngFor="let type of authMethodTypes" [value]="type.type">
<span *ngIf="type.oidc">{{ 'APP.OIDC.AUTHMETHOD.' + type.type | translate }}</span>
<span *ngIf="type.api">{{ 'APP.API.AUTHMETHOD.' + type.type | translate }}</span>
</mat-option>
</mat-select>
</cnsl-form-field>
</div>
<div class="content" *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
<div class="formfield full-width">
<cnsl-redirect-uris
class="redirect-section"
[canWrite]="true"
(changedUris)="oidcAppRequest.redirectUrisList = $any($event)"
[urisList]="oidcAppRequest.redirectUrisList"
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
[getValues]="requestRedirectValuesSubject$"
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
<cnsl-redirect-uris
class="redirect-section"
[canWrite]="true"
(changedUris)="oidcAppRequest.postLogoutRedirectUrisList = $any($event)"
[urisList]="oidcAppRequest.postLogoutRedirectUrisList"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
[getValues]="requestRedirectValuesSubject$"
[isNative]="oidcAppRequest.appType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
</div>
</div>
<button
color="primary"
mat-raised-button
class="continue-button"
[disabled]="form.invalid"
cdkFocusInitial
type="submit"
>
{{ 'ACTIONS.CREATE' | translate }}
</button>
</form>
</div>
</div>
</div>
<button
color="primary"
mat-raised-button
class="continue-button"
[disabled]="form.invalid"
cdkFocusInitial
type="submit"
>
{{ 'ACTIONS.CREATE' | translate }}
</button>
</form>
</div>
</div>
</cnsl-create-layout>
@@ -12,122 +12,101 @@ p.desc {
display: block;
}
.abort-container {
.name-formfield {
max-width: 400px;
display: block;
}
.app-create-container {
padding-top: 2rem;
.progress-bar {
margin-bottom: 1rem;
}
}
.margin-right {
margin-right: 0.5rem;
}
.full-width {
width: 100%;
}
.stepper {
background: inherit !important;
margin: 0 -1.5rem;
.formfield {
max-width: 400px;
}
.step-title {
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.step-description {
font-size: 0.9rem;
}
}
.checkbox-container {
display: flex;
flex-direction: column;
.checkbox {
margin: 0.5rem 0;
}
}
.row {
display: flex;
justify-content: space-between;
.left,
.right {
margin-bottom: 0.5rem;
font-size: 14px;
}
}
.app-create-actions {
margin-top: 1rem;
display: flex;
align-items: center;
margin-bottom: 2rem;
.abort {
font-size: 1.2rem;
margin-left: 2rem;
.bck-button {
margin-right: 1rem;
}
.abort-2 {
font-size: 1.2rem;
margin-left: 2rem;
white-space: nowrap;
.create-button {
padding: 0.5rem 4rem;
}
}
.app-create-content {
padding-left: 4.5rem;
.name-formfield {
max-width: 400px;
display: block;
}
.app-create-container {
padding-top: 2rem;
.progress-bar {
margin-bottom: 1rem;
}
}
.margin-right {
margin-right: 0.5rem;
}
.full-width {
width: 100%;
}
.stepper {
background: inherit !important;
margin: 0 -1.5rem;
.dev {
.content {
display: flex;
margin: 0 -0.5rem;
flex-wrap: wrap;
flex-direction: row;
.formfield {
max-width: 400px;
}
flex: 1;
box-sizing: border-box;
margin: 0 0.5rem;
.step-title {
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.step-description {
font-size: 0.9rem;
}
}
.checkbox-container {
display: flex;
flex-direction: column;
.checkbox {
margin: 0.5rem 0;
}
}
.row {
display: flex;
justify-content: space-between;
.left,
.right {
margin-bottom: 0.5rem;
font-size: 14px;
}
}
.app-create-actions {
margin-top: 1rem;
display: flex;
align-items: center;
.bck-button {
margin-right: 1rem;
}
.create-button {
padding: 0.5rem 4rem;
}
}
.dev {
.content {
display: flex;
margin: 0 -0.5rem;
flex-wrap: wrap;
flex-direction: row;
.formfield {
flex: 1;
box-sizing: border-box;
margin: 0 0.5rem;
&.full-width {
flex-basis: 80%;
}
&.full-width {
flex-basis: 80%;
}
}
}
.continue-button {
margin-top: 3rem;
display: block;
padding: 0.5rem 4rem;
}
.continue-button {
margin-top: 3rem;
display: block;
padding: 0.5rem 4rem;
}
}
@@ -1,150 +1,90 @@
<cnsl-top-view title="{{app?.name}}"
[hasActions]="isZitadel === false && (['project.app.write:'+projectId, 'project.app.write'] | hasRole | async)"
docLink="https://docs.zitadel.com/docs/guides/basics/projects"
[sub]="app?.oidcConfig ? ('APP.OIDC.APPTYPE.'+app?.oidcConfig?.appType | translate): 'API'"
[isActive]="app?.state === AppState.APP_STATE_ACTIVE" [isInactive]="app?.state === AppState.APP_STATE_INACTIVE"
stateTooltip="{{('APP.PAGES.DETAIL.STATE.'+app?.state) | translate}}">
<ng-template topActions cnslHasRole [hasRole]="['project.app.write:'+projectId, 'project.app.write']">
<div class="regen-secret"
*ngIf="isZitadel === false && this.app?.oidcConfig && (currentAuthMethod === 'CODE' || currentAuthMethod === 'POST')">
<button type="button" [disabled]="!canWrite" mat-menu-item
(click)="regenerateOIDCClientSecret()">{{'APP.OIDC.REGENERATESECRET' | translate}}</button>
<cnsl-top-view
title="{{ app?.name }}"
[hasActions]="isZitadel === false && (['project.app.write:' + projectId, 'project.app.write'] | hasRole | async)"
docLink="https://docs.zitadel.ch/docs/guides/basics/projects"
[sub]="app?.oidcConfig ? ('APP.OIDC.APPTYPE.' + app?.oidcConfig?.appType | translate) : 'API'"
[isActive]="app?.state === AppState.APP_STATE_ACTIVE"
[isInactive]="app?.state === AppState.APP_STATE_INACTIVE"
stateTooltip="{{ 'APP.PAGES.DETAIL.STATE.' + app?.state | translate }}"
>
<ng-template topActions cnslHasRole [hasRole]="['project.app.write:' + projectId, 'project.app.write']">
<div
class="regen-secret"
*ngIf="isZitadel === false && this.app?.oidcConfig && (currentAuthMethod === 'CODE' || currentAuthMethod === 'POST')"
>
<button type="button" [disabled]="!canWrite" mat-menu-item (click)="regenerateOIDCClientSecret()">
{{ 'APP.OIDC.REGENERATESECRET' | translate }}
</button>
</div>
<div class="regen-secret" *ngIf="isZitadel === false && this.app?.apiConfig && currentAuthMethod === 'BASIC'">
<button [disabled]="!canWrite" mat-menu-item (click)="regenerateAPIClientSecret()">{{'APP.API.REGENERATESECRET' |
translate}}</button>
<button [disabled]="!canWrite" mat-menu-item (click)="regenerateAPIClientSecret()">
{{ 'APP.API.REGENERATESECRET' | translate }}
</button>
</div>
<button *ngIf="isZitadel === false" mat-menu-item (click)="openNameDialog()" aria-label="Edit project name">
{{'ACTIONS.RENAME' | translate}}
{{ 'ACTIONS.RENAME' | translate }}
</button>
<button mat-menu-item *ngIf="isZitadel === false && app?.state !== AppState.APP_STATE_INACTIVE"
(click)="changeState(AppState.APP_STATE_INACTIVE)">
{{'ACTIONS.DEACTIVATE' | translate}}
<button
mat-menu-item
*ngIf="isZitadel === false && app?.state !== AppState.APP_STATE_INACTIVE"
(click)="changeState(AppState.APP_STATE_INACTIVE)"
>
{{ 'ACTIONS.DEACTIVATE' | translate }}
</button>
<button mat-menu-item *ngIf="isZitadel === false && app?.state === AppState.APP_STATE_INACTIVE"
(click)="changeState(AppState.APP_STATE_ACTIVE)">
{{'ACTIONS.REACTIVATE' | translate}}
<button
mat-menu-item
*ngIf="isZitadel === false && app?.state === AppState.APP_STATE_INACTIVE"
(click)="changeState(AppState.APP_STATE_ACTIVE)"
>
{{ 'ACTIONS.REACTIVATE' | translate }}
</button>
<ng-template cnslHasRole [hasRole]="['project.app.delete:'+projectId, 'project.app.delete']">
<button *ngIf="isZitadel === false" mat-menu-item matTooltip="{{'APP.PAGES.DELETE' | translate}}"
(click)="deleteApp()">
<span [style.color]="'var(--warn)'">{{'APP.PAGES.DELETE' | translate}}</span>
<ng-template cnslHasRole [hasRole]="['project.app.delete:' + projectId, 'project.app.delete']">
<button
*ngIf="isZitadel === false"
mat-menu-item
matTooltip="{{ 'APP.PAGES.DELETE' | translate }}"
(click)="deleteApp()"
>
<span [style.color]="'var(--warn)'">{{ 'APP.PAGES.DELETE' | translate }}</span>
</button>
</ng-template>
</ng-template>
<span *ngIf="errorMessage" class="app-err-container">{{errorMessage}}</span>
<span *ngIf="errorMessage" class="app-err-container">{{ errorMessage }}</span>
<cnsl-info-row topContent *ngIf="app" [app]="app"></cnsl-info-row>
</cnsl-top-view>
<div class="max-width-container">
<cnsl-auth-method-radio *ngIf="authMethods && initialAuthMethod && (app?.oidcConfig || app?.apiConfig)"
[authMethods]="authMethods" [selected]="initialAuthMethod" [current]="currentAuthMethod"
[isOIDC]="app?.oidcConfig !== undefined" (selectedMethod)="setPartialConfigFromAuthMethod($event)">
</cnsl-auth-method-radio>
<div class="compliance" *ngIf="app?.oidcConfig?.complianceProblemsList && app.oidcConfig?.complianceProblemsList?.length">
<h2 class="compliance-title">{{ 'APP.COMPLIANCE' | translate }}</h2>
<cnsl-info-section class="problem" [type]="InfoSectionType.ALERT">
<ul style="margin: 0">
<li style="margin: 0 0 0.5rem 0" *ngFor="let problem of app.oidcConfig?.complianceProblemsList || []">
{{ problem.localizedMessage }}
</li>
</ul>
</cnsl-info-section>
</div>
<div class="app-main-content">
<cnsl-meta-layout>
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList">
<ng-container *ngIf="currentSetting === 'redirect-uris'">
<cnsl-card title=" {{ 'APP.OIDC.REDIRECTSECTIONTITLE' | translate }}">
<cnsl-info-section *ngIf="appType?.value === OIDCAppType.OIDC_APP_TYPE_NATIVE">
<div class="dev-col">
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</span>
<mat-slide-toggle *ngIf="devMode" color="primary" class="devmode" [formControl]="devMode" name="devMode"
matTooltip="{{'APP.OIDC.DEVMODEDESC' | translate}}">
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
</div>
</cnsl-info-section>
<cnsl-info-section
*ngIf="appType?.value === OIDCAppType.OIDC_APP_TYPE_WEB || appType?.value === OIDCAppType.OIDC_APP_TYPE_USER_AGENT">
<div class="dev-col">
<span>{{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}</span>
<mat-slide-toggle *ngIf="devMode" color="primary" class="devmode" [formControl]="devMode" name="devMode"
matTooltip="{{'APP.OIDC.DEVMODEDESC' | translate}}">
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
</div>
</cnsl-info-section>
<cnsl-redirect-uris *ngIf="appType?.value !== undefined" class="redirect-section" [canWrite]="canWrite"
[devMode]="devMode?.value" [getValues]="requestRedirectValuesSubject$"
(changedUris)="redirectUrisList = $any($event)" [urisList]="redirectUrisList"
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
[isNative]="appType?.value === OIDCAppType.OIDC_APP_TYPE_NATIVE">
</cnsl-redirect-uris>
<cnsl-redirect-uris *ngIf="appType?.value !== undefined" class="redirect-section" [canWrite]="canWrite"
[devMode]="devMode?.value" (changedUris)="postLogoutRedirectUrisList = $any($event)"
[urisList]="postLogoutRedirectUrisList" [getValues]="requestRedirectValuesSubject$"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
[isNative]="appType?.value === OIDCAppType.OIDC_APP_TYPE_NATIVE">
</cnsl-redirect-uris>
<div class="btn-container">
<button class="submit-button" color="primary" (click)="saveOIDCApp()" [disabled]="!canWrite"
mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'additional-origins'">
<cnsl-card title=" {{ 'APP.ADDITIONALORIGINS' | translate }}">
<p class="app-desc cnsl-secondary-text">{{'APP.ADDITIONALORIGINSDESC' | translate}}</p>
<cnsl-additional-origins *ngIf="additionalOriginsList && appType && appType?.value !== undefined"
class="app-input" [canWrite]="canWrite" [getValues]="requestRedirectValuesSubject$"
(changedUris)="additionalOriginsListChanged($event)" [urisList]="additionalOriginsList"
title="{{ 'APP.ORIGINS' | translate }}">
</cnsl-additional-origins>
<div class="btn-container">
<button class="submit-button" (click)="saveOIDCApp()" color="primary" [disabled]="!canWrite"
mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'urls'">
<cnsl-card title=" {{ 'APP.URLS' | translate }}">
<div class="app-info-row">
<div class="app-info-wrapper" *ngFor="let environmentV of (environmentMap | keyvalue)">
<p class="app-info-row-title cnsl-secondary-text">{{environmentV.key}}</p>
<div class="app-copy-row">
<div *ngIf="environmentV.value" class="environment">
<button [disabled]="copied === environmentV.value"
[matTooltip]="(copied !== environmentV.value ? 'ACTIONS.COPY' : 'ACTIONS.COPIED' ) | translate"
cnslCopyToClipboard [valueToCopy]="environmentV.value" (copiedValue)="copied = environmentV.key">
{{environmentV.value}}
</button>
</div>
</div>
</div>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'configuration'">
<cnsl-card *ngIf="oidcForm && app?.oidcConfig" title=" {{ 'APP.OIDC.TITLE' | translate }}">
<form [formGroup]="oidcForm" (ngSubmit)="saveOIDCApp()">
<div class="compliance"
*ngIf="app?.oidcConfig?.complianceProblemsList && app.oidcConfig?.complianceProblemsList?.length">
<h2 class="compliance-title">{{'APP.COMPLIANCE' | translate}}</h2>
<cnsl-info-section class="problem" [type]="InfoSectionType.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="current-auth-method"
*ngIf="currentRadioItemAuthType"
[ngStyle]="{ background: currentRadioItemAuthType.background }"
>
<h3>{{ currentRadioItemAuthType.titleI18nKey | translate }}</h3>
<p>{{ currentRadioItemAuthType.descI18nKey | translate }}</p>
<span class="fill-space"></span>
<button mat-icon-button (click)="changeAuthMethod()"><i class="las la-pen"></i></button>
</div>
<form [formGroup]="oidcForm" (ngSubmit)="saveOIDCApp()">
<div class="app-oidc-content">
<div class="app-oidc-grid">
<cnsl-form-field class="app-formfield" appearance="outline">
@@ -156,7 +96,7 @@
<cnsl-label>{{ 'APP.TYPE' | translate }}</cnsl-label>
<mat-select formControlName="appType">
<mat-option *ngFor="let type of oidcAppTypes" [value]="type">
{{ 'APP.OIDC.APPTYPE.'+type | translate }}
{{ 'APP.OIDC.APPTYPE.' + type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
@@ -165,7 +105,7 @@
<cnsl-label>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</cnsl-label>
<mat-select formControlName="responseTypesList" multiple>
<mat-option *ngFor="let type of oidcResponseTypes" [value]="type">
{{ 'APP.OIDC.RESPONSE.'+type | translate }}
{{ 'APP.OIDC.RESPONSE.' + type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
@@ -174,7 +114,7 @@
<cnsl-label>{{ 'APP.AUTHMETHOD' | translate }}</cnsl-label>
<mat-select formControlName="authMethodType">
<mat-option *ngFor="let type of oidcAuthMethodType" [value]="type">
{{ 'APP.OIDC.AUTHMETHOD.'+type | translate }}
{{ 'APP.OIDC.AUTHMETHOD.' + type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
@@ -183,62 +123,31 @@
<cnsl-label>{{ 'APP.OIDC.GRANTTYPE' | translate }}</cnsl-label>
<mat-select formControlName="grantTypesList" multiple>
<mat-option *ngFor="let grant of oidcGrantTypes" [value]="grant">
{{ 'APP.OIDC.GRANT.'+grant | translate }}
{{ 'APP.OIDC.GRANT.' + grant | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<mat-checkbox color="primary" class="rt" (change)="toggleRefreshToken($event)"
<mat-checkbox
color="primary"
class="rt"
(change)="toggleRefreshToken($event)"
[disabled]="!this.grantTypesList?.value.includes(OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE)"
[checked]="this.grantTypesList?.value.includes(OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN)">
[checked]="this.grantTypesList?.value.includes(OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN)"
>
{{ 'APP.OIDC.REFRESHTOKEN' | translate }}
</mat-checkbox>
</div>
<p class="app-full-width app-section-title">{{'APP.OIDC.TOKENSECTIONTITLE' | translate}}</p>
<cnsl-form-field appearance="outline" class="app-formfield">
<cnsl-label>{{ 'APP.OIDC.TOKENTYPE' | translate }}</cnsl-label>
<mat-select formControlName="accessTokenType">
<mat-option *ngFor="let type of oidcTokenTypes" [value]="type">
{{ 'APP.OIDC.TOKENTYPE'+type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<mat-checkbox *ngIf="accessTokenType?.value === OIDCTokenType.OIDC_TOKEN_TYPE_JWT" class="full-width"
formControlName="accessTokenRoleAssertion" color="primary">
{{'APP.OIDC.ACCESSTOKENROLEASSERTION' | translate}}</mat-checkbox>
<cnsl-info-section class="app-full-width app-desc">
<span>{{'APP.OIDC.ACCESSTOKENROLEASSERTION_DESCRIPTION' | translate}}</span>
</cnsl-info-section>
<mat-checkbox class="app-full-width" style="margin-top: 1.5rem" formControlName="idTokenRoleAssertion"
color="primary">
{{'APP.OIDC.IDTOKENROLEASSERTION' | translate}}</mat-checkbox>
<cnsl-info-section class="full-width app-desc">
<span>{{'APP.OIDC.IDTOKENROLEASSERTION_DESCRIPTION' | translate}}</span>
</cnsl-info-section>
<mat-checkbox class="app-full-width" style="margin-top: 1.5rem"
formControlName="idTokenUserinfoAssertion" color="primary">
{{'APP.OIDC.IDTOKENUSERINFOASSERTION' | translate}}</mat-checkbox>
<cnsl-info-section class="app-full-width app-desc">
<span>{{'APP.OIDC.IDTOKENUSERINFOASSERTION_DESCRIPTION' | translate}}</span>
</cnsl-info-section>
<p class="clockskew-title cnsl-secondary-text">ClockSkew</p>
<mat-slider color="primary" formControlName="clockSkewSeconds" class="clockskew-slider" thumbLabel
[displayWith]="formatClockSkewLabel" tickInterval=".1" min="0" [step]="1" max="5">
</mat-slider>
<cnsl-info-section class="app-full-width app-desc">
<span>{{'APP.OIDC.CLOCKSKEW' | translate}}</span>
</cnsl-info-section>
</div>
<div class="btn-container">
<button class="submit-button" type="submit" color="primary" [disabled]="oidcForm.invalid || !canWrite"
mat-raised-button>
<button
class="submit-button"
type="submit"
color="primary"
[disabled]="oidcForm.invalid || !canWrite"
mat-raised-button
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
@@ -246,14 +155,220 @@
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'token'">
<cnsl-card *ngIf="oidcTokenForm && app?.oidcConfig" title=" {{ 'APP.OIDC.TOKENSECTIONTITLE' | translate }}">
<form [formGroup]="oidcTokenForm" (ngSubmit)="saveOIDCApp()">
<cnsl-form-field appearance="outline" class="app-formfield">
<cnsl-label>{{ 'APP.OIDC.TOKENTYPE' | translate }}</cnsl-label>
<mat-select formControlName="accessTokenType">
<mat-option *ngFor="let type of oidcTokenTypes" [value]="type">
{{ 'APP.OIDC.TOKENTYPE' + type | translate }}
</mat-option>
</mat-select>
</cnsl-form-field>
<mat-checkbox
*ngIf="accessTokenType?.value === OIDCTokenType.OIDC_TOKEN_TYPE_JWT"
class="full-width"
style="margin-top: 1.5rem"
formControlName="accessTokenRoleAssertion"
color="primary"
>
{{ 'APP.OIDC.ACCESSTOKENROLEASSERTION' | translate }}</mat-checkbox
>
<cnsl-info-section class="full-width app-desc">
<span>{{ 'APP.OIDC.ACCESSTOKENROLEASSERTION_DESCRIPTION' | translate }}</span>
</cnsl-info-section>
<mat-checkbox
class="full-width"
style="margin-top: 1.5rem"
formControlName="idTokenRoleAssertion"
color="primary"
>
{{ 'APP.OIDC.IDTOKENROLEASSERTION' | translate }}</mat-checkbox
>
<cnsl-info-section class="full-width app-desc">
<span>{{ 'APP.OIDC.IDTOKENROLEASSERTION_DESCRIPTION' | translate }}</span>
</cnsl-info-section>
<mat-checkbox
class="full-width"
style="margin-top: 1.5rem"
formControlName="idTokenUserinfoAssertion"
color="primary"
>
{{ 'APP.OIDC.IDTOKENUSERINFOASSERTION' | translate }}</mat-checkbox
>
<cnsl-info-section class="full-width app-desc">
<span>{{ 'APP.OIDC.IDTOKENUSERINFOASSERTION_DESCRIPTION' | translate }}</span>
</cnsl-info-section>
<p class="clockskew-title cnsl-secondary-text">ClockSkew</p>
<mat-slider
color="primary"
formControlName="clockSkewSeconds"
class="clockskew-slider"
thumbLabel
[displayWith]="formatClockSkewLabel"
tickInterval=".1"
min="0"
[step]="1"
max="5"
>
</mat-slider>
<cnsl-info-section class="full-width app-desc">
<span>{{ 'APP.OIDC.CLOCKSKEW' | translate }}</span>
</cnsl-info-section>
<div class="btn-container">
<button
class="submit-button"
type="submit"
color="primary"
[disabled]="oidcTokenForm.invalid || !canWrite"
mat-raised-button
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</form>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'redirect-uris'">
<cnsl-card title=" {{ 'APP.OIDC.REDIRECTSECTIONTITLE' | translate }}">
<cnsl-info-section *ngIf="appType?.value === OIDCAppType.OIDC_APP_TYPE_NATIVE">
<div class="dev-col">
<span>{{ 'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate }}</span>
<mat-slide-toggle
*ngIf="devMode"
color="primary"
class="devmode"
[formControl]="devMode"
name="devMode"
matTooltip="{{ 'APP.OIDC.DEVMODEDESC' | translate }}"
>
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
</div>
</cnsl-info-section>
<cnsl-info-section
*ngIf="
appType?.value === OIDCAppType.OIDC_APP_TYPE_WEB || appType?.value === OIDCAppType.OIDC_APP_TYPE_USER_AGENT
"
>
<div class="dev-col">
<span>{{ 'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate }}</span>
<mat-slide-toggle
*ngIf="devMode"
color="primary"
class="devmode"
[formControl]="devMode"
name="devMode"
matTooltip="{{ 'APP.OIDC.DEVMODEDESC' | translate }}"
>
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
</div>
</cnsl-info-section>
<cnsl-redirect-uris
*ngIf="appType?.value !== undefined"
class="redirect-section"
[canWrite]="canWrite"
[devMode]="devMode?.value"
[getValues]="requestRedirectValuesSubject$"
(changedUris)="redirectUrisList = $any($event)"
[urisList]="redirectUrisList"
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
[isNative]="appType?.value === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
<cnsl-redirect-uris
*ngIf="appType?.value !== undefined"
class="redirect-section"
[canWrite]="canWrite"
[devMode]="devMode?.value"
(changedUris)="postLogoutRedirectUrisList = $any($event)"
[urisList]="postLogoutRedirectUrisList"
[getValues]="requestRedirectValuesSubject$"
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
[isNative]="appType?.value === OIDCAppType.OIDC_APP_TYPE_NATIVE"
>
</cnsl-redirect-uris>
<div class="btn-container">
<button class="submit-button" color="primary" (click)="saveOIDCApp()" [disabled]="!canWrite" mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'additional-origins'">
<cnsl-card title=" {{ 'APP.ADDITIONALORIGINS' | translate }}">
<p class="app-desc cnsl-secondary-text">{{ 'APP.ADDITIONALORIGINSDESC' | translate }}</p>
<cnsl-additional-origins
*ngIf="additionalOriginsList && appType && appType?.value !== undefined"
class="app-input"
[canWrite]="canWrite"
[getValues]="requestRedirectValuesSubject$"
(changedUris)="additionalOriginsListChanged($event)"
[urisList]="additionalOriginsList"
title="{{ 'APP.ORIGINS' | translate }}"
>
</cnsl-additional-origins>
<div class="btn-container">
<button class="submit-button" (click)="saveOIDCApp()" color="primary" [disabled]="!canWrite" mat-raised-button>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'urls'">
<cnsl-card title=" {{ 'APP.URLS' | translate }}">
<div class="app-info-row">
<div class="app-info-wrapper" *ngFor="let environmentV of environmentMap | keyvalue">
<p class="app-info-row-title cnsl-secondary-text">{{ environmentV.key }}</p>
<div class="app-copy-row">
<div *ngIf="environmentV.value" class="environment">
<button
[disabled]="copied === environmentV.value"
[matTooltip]="(copied !== environmentV.value ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="environmentV.value"
(copiedValue)="copied = environmentV.key"
>
{{ environmentV.value }}
</button>
</div>
</div>
</div>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'configuration'">
<cnsl-card *ngIf="currentAuthMethod === 'PK_JWT' && projectId && app?.id"
title="{{ 'USER.MACHINE.KEYSTITLE' | translate }}" description="{{ 'USER.MACHINE.KEYSDESC' | translate }}">
<cnsl-card
*ngIf="initialAuthMethod === 'PK_JWT' && projectId && app?.id"
title="{{ 'USER.MACHINE.KEYSTITLE' | translate }}"
description="{{ 'USER.MACHINE.KEYSDESC' | translate }}"
>
<cnsl-client-keys [projectId]="projectId" [appId]="app.id"></cnsl-client-keys>
<div *ngIf="apiForm && app?.apiConfig" class="btn-container">
<button class="submit-button" (click)="saveAPIApp()" color="primary"
[disabled]="apiForm.invalid || !canWrite" mat-raised-button>
<button
class="submit-button"
(click)="saveAPIApp()"
color="primary"
[disabled]="apiForm.invalid || !canWrite"
mat-raised-button
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
</div>
@@ -261,11 +376,9 @@
</ng-container>
</cnsl-sidenav>
<!-- <cnsl-links [links]="nextLinks"></cnsl-links> -->
<div metainfo>
<cnsl-changes *ngIf="app" [changeType]="ChangeType.APP" [id]="app.id" [secId]="projectId"></cnsl-changes>
</div>
</cnsl-meta-layout>
</div>
</div>
</div>
@@ -44,11 +44,6 @@
flex-direction: column;
margin: 0 -0.5rem;
@media only screen and (min-width: 500px) {
flex-direction: row;
flex-wrap: wrap;
}
.app-info-wrapper {
display: flex;
flex-direction: column;
@@ -77,6 +72,7 @@
flex-direction: column;
width: 100%;
align-items: stretch;
margin-bottom: 0.5rem;
button {
transition: opacity 0.15s ease-in-out;
@@ -109,22 +105,53 @@
}
}
.compliance {
padding-bottom: 1rem;
padding-top: 0.5rem;
border-bottom: 1px solid $divider-color;
.compliance-title {
margin: 1rem 0 1rem 0;
font-size: 16px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.problem {
font-size: 14px;
margin: 0 0 0.5rem 0;
display: block;
}
}
.app-main-content {
border-top: 1px solid $divider-color;
margin-top: 1.5rem;
}
}
margin-top: 0.5rem;
.compliance {
.compliance-title {
margin: 1rem 0 1rem 0;
font-size: 16px;
}
.current-auth-method {
display: flex;
align-items: center;
border: 1px solid if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
border-radius: 0.5rem;
padding: 0.5rem 1rem;
margin-bottom: 1rem;
.problem {
font-size: 14px;
margin: 0 0 0.5rem 0;
display: block;
h3 {
margin: 0 1rem 0 0;
}
p {
font-size: 14px;
margin: 0;
}
.fill-space {
flex: 1;
}
button {
margin-left: 1rem;
}
}
}
}
@@ -5,7 +5,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
@@ -14,7 +13,6 @@ 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 { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
import { CnslLinks } from 'src/app/modules/links/links.component';
import { NameDialogComponent } from 'src/app/modules/name-dialog/name-dialog.component';
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
@@ -52,6 +50,7 @@ import {
PKCE_METHOD,
POST_METHOD,
} from '../authmethods';
import { AuthMethodDialogComponent } from './auth-method-dialog/auth-method-dialog.component';
@Component({
selector: 'cnsl-app-detail',
@@ -103,6 +102,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public AppState: any = AppState;
public oidcForm!: FormGroup;
public oidcTokenForm!: FormGroup;
public apiForm!: FormGroup;
public redirectUrisList: string[] = [];
@@ -122,7 +122,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public requestRedirectValuesSubject$: Subject<void> = new Subject();
public copiedKey: any = '';
public nextLinks: Array<CnslLinks> = [];
public InfoSectionType: any = InfoSectionType;
public copied: string = '';
@@ -139,7 +138,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
private mgmtService: ManagementService,
private authService: GrpcAuthService,
private router: Router,
private snackbar: MatSnackBar,
private breadcrumbService: BreadcrumbService,
private http: HttpClient,
) {
@@ -150,6 +148,9 @@ export class AppDetailComponent implements OnInit, OnDestroy {
grantTypesList: [{ value: [], disabled: true }],
appType: [{ value: '', disabled: true }],
authMethodType: [{ value: '', disabled: true }],
});
this.oidcTokenForm = this.fb.group({
accessTokenType: [{ value: '', disabled: true }],
accessTokenRoleAssertion: [{ value: false, disabled: true }],
idTokenRoleAssertion: [{ value: false, disabled: true }],
@@ -212,32 +213,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.subscription?.unsubscribe();
}
private initLinks(): void {
this.nextLinks = [
{
i18nTitle: 'APP.PAGES.NEXTSTEPS.0.TITLE',
i18nDesc: 'APP.PAGES.NEXTSTEPS.0.DESC',
routerLink: ['/projects', this.projectId, 'roles'],
iconClasses: 'las la-user-tag',
},
{
i18nTitle: 'APP.PAGES.NEXTSTEPS.1.TITLE',
i18nDesc: 'APP.PAGES.NEXTSTEPS.1.DESC',
routerLink: ['/users', 'create'],
iconClasses: 'las la-user-plus',
},
{
i18nTitle: 'APP.PAGES.NEXTSTEPS.2.TITLE',
i18nDesc: 'APP.PAGES.NEXTSTEPS.2.DESC',
href: 'https://docs.zitadel.comm',
iconClasses: 'las la-people-carry',
},
];
}
private async getData(projectId: string, appId: string): Promise<void> {
this.initLinks();
this.mgmtService.getIAM().then((iam) => {
this.isZitadel = iam.iamProjectId === this.projectId;
});
@@ -277,6 +253,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.settingsList = [
{ id: 'configuration', i18nKey: 'APP.CONFIGURATION' },
{ id: 'token', i18nKey: 'APP.TOKEN' },
{ id: 'redirect-uris', i18nKey: 'APP.OIDC.REDIRECTSECTIONTITLE' },
{ id: 'additional-origins', i18nKey: 'APP.ADDITIONALORIGINS' },
{ id: 'urls', i18nKey: 'APP.URLS' },
@@ -317,6 +294,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
if (allowed) {
this.oidcForm.enable();
this.oidcTokenForm.enable();
this.apiForm.enable();
}
@@ -332,10 +310,11 @@ export class AppDetailComponent implements OnInit, OnDestroy {
if (this.app.oidcConfig?.clockSkew) {
const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000;
this.oidcForm.controls['clockSkewSeconds'].setValue(inSecs);
this.oidcTokenForm.controls['clockSkewSeconds'].setValue(inSecs);
}
if (this.app.oidcConfig) {
this.oidcForm.patchValue(this.app.oidcConfig);
this.oidcTokenForm.patchValue(this.app.oidcConfig);
}
if (this.app.apiConfig) {
this.apiForm.patchValue(this.app.apiConfig);
@@ -350,8 +329,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
} else {
this.authMethods = this.authMethods.filter((element) => element !== CUSTOM_METHOD);
}
this.showSaveSnack();
});
this.apiForm.valueChanges.subscribe((apiConfig) => {
@@ -363,8 +340,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
} else {
this.authMethods = this.authMethods.filter((element) => element !== CUSTOM_METHOD);
}
this.showSaveSnack();
});
}
})
@@ -377,20 +352,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.docs = await this.mgmtService.getOIDCInformation();
}
private async showSaveSnack(): Promise<void> {
const message = await this.translate.get('APP.TOAST.CONFIGCHANGED').toPromise();
const action = await this.translate.get('ACTIONS.SAVENOW').toPromise();
const snackRef = this.snackbar.open(message, action, { duration: 5000, verticalPosition: 'top' });
snackRef.onAction().subscribe(() => {
if (this.app.oidcConfig) {
this.saveOIDCApp();
} else if (this.app.apiConfig) {
this.saveAPIApp();
}
});
}
private getAuthMethodOptions(type: string): void {
if (type === 'OIDC') {
switch (this.app.oidcConfig?.appType) {
@@ -426,6 +387,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
(partialConfig.oidc as Partial<OIDCConfig.AsObject>).authMethodType ?? OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE;
this.oidcForm.patchValue(this.app.oidcConfig);
this.oidcTokenForm.patchValue(this.app.oidcConfig);
} else if (partialConfig && partialConfig.api && this.app.apiConfig) {
this.app.apiConfig.authMethodType =
(partialConfig.api as Partial<APIConfig.AsObject>).authMethodType ?? APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC;
@@ -444,6 +406,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
},
width: '400px',
});
dialogRef.afterClosed().subscribe((resp) => {
if (resp && this.projectId && this.app.id) {
this.mgmtService
@@ -519,40 +482,53 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.requestRedirectValuesSubject$.next();
if (this.oidcForm.valid) {
if (this.app.oidcConfig) {
// configuration
this.app.oidcConfig.responseTypesList = this.responseTypesList?.value;
this.app.oidcConfig.grantTypesList = this.grantTypesList?.value;
this.app.oidcConfig.appType = this.appType?.value;
this.app.oidcConfig.authMethodType = this.authMethodType?.value;
this.app.oidcConfig.redirectUrisList = this.redirectUrisList;
this.app.oidcConfig.postLogoutRedirectUrisList = this.postLogoutRedirectUrisList;
this.app.oidcConfig.additionalOriginsList = this.additionalOriginsList;
this.app.oidcConfig.devMode = this.devMode?.value;
// token
this.app.oidcConfig.accessTokenType = this.accessTokenType?.value;
this.app.oidcConfig.accessTokenRoleAssertion = this.accessTokenRoleAssertion?.value;
this.app.oidcConfig.idTokenRoleAssertion = this.idTokenRoleAssertion?.value;
this.app.oidcConfig.idTokenUserinfoAssertion = this.idTokenUserinfoAssertion?.value;
// redirects
this.app.oidcConfig.redirectUrisList = this.redirectUrisList;
this.app.oidcConfig.postLogoutRedirectUrisList = this.postLogoutRedirectUrisList;
this.app.oidcConfig.additionalOriginsList = this.additionalOriginsList;
this.app.oidcConfig.devMode = this.devMode?.value;
const req = new UpdateOIDCAppConfigRequest();
req.setProjectId(this.projectId);
req.setAppId(this.app.id);
req.setRedirectUrisList(this.app.oidcConfig.redirectUrisList);
// configuration
req.setResponseTypesList(this.app.oidcConfig.responseTypesList);
req.setAdditionalOriginsList(this.app.oidcConfig.additionalOriginsList);
req.setAuthMethodType(this.app.oidcConfig.authMethodType);
req.setPostLogoutRedirectUrisList(this.app.oidcConfig.postLogoutRedirectUrisList);
req.setGrantTypesList(this.app.oidcConfig.grantTypesList);
req.setAppType(this.app.oidcConfig.appType);
req.setDevMode(this.app.oidcConfig.devMode);
// token
req.setAccessTokenType(this.app.oidcConfig.accessTokenType);
req.setAccessTokenRoleAssertion(this.app.oidcConfig.accessTokenRoleAssertion);
req.setIdTokenRoleAssertion(this.app.oidcConfig.idTokenRoleAssertion);
req.setIdTokenUserinfoAssertion(this.app.oidcConfig.idTokenUserinfoAssertion);
// redirects
req.setRedirectUrisList(this.app.oidcConfig.redirectUrisList);
req.setAdditionalOriginsList(this.app.oidcConfig.additionalOriginsList);
req.setPostLogoutRedirectUrisList(this.app.oidcConfig.postLogoutRedirectUrisList);
req.setDevMode(this.app.oidcConfig.devMode);
if (this.clockSkewSeconds?.value) {
const dur = new Duration();
dur.setSeconds(Math.floor(this.clockSkewSeconds?.value));
dur.setNanos(Math.floor(this.clockSkewSeconds?.value % 1) * 10000);
req.setClockSkew(dur);
}
this.mgmtService
.updateOIDCAppConfig(req)
.then(() => {
@@ -622,6 +598,24 @@ export class AppDetailComponent implements OnInit, OnDestroy {
});
}
public changeAuthMethod(): void {
const ref = this.dialog.open(AuthMethodDialogComponent, {
data: {
radioItemAuthType: this.currentRadioItemAuthType,
initialAuthMethod: this.initialAuthMethod,
currentAuthMethod: this.currentAuthMethod,
authMethods: this.authMethods,
isOIDC: this.app?.oidcConfig !== undefined,
},
});
ref.afterClosed().subscribe((authMethod: string) => {
if (authMethod) {
this.setPartialConfigFromAuthMethod(authMethod);
}
});
}
public regenerateAPIClientSecret(): void {
this.mgmtService
.regenerateAPIClientSecret(this.app.id, this.projectId)
@@ -639,6 +633,10 @@ export class AppDetailComponent implements OnInit, OnDestroy {
});
}
public get currentRadioItemAuthType(): RadioItemAuthType | undefined {
return this.authMethods.find((i) => i.key === this.initialAuthMethod);
}
public navigateBack(): void {
this._location.back();
}
@@ -672,22 +670,22 @@ export class AppDetailComponent implements OnInit, OnDestroy {
}
public get accessTokenType(): AbstractControl | null {
return this.oidcForm.get('accessTokenType');
return this.oidcTokenForm.get('accessTokenType');
}
public get idTokenRoleAssertion(): AbstractControl | null {
return this.oidcForm.get('idTokenRoleAssertion');
return this.oidcTokenForm.get('idTokenRoleAssertion');
}
public get accessTokenRoleAssertion(): AbstractControl | null {
return this.oidcForm.get('accessTokenRoleAssertion');
return this.oidcTokenForm.get('accessTokenRoleAssertion');
}
public get idTokenUserinfoAssertion(): AbstractControl | null {
return this.oidcForm.get('idTokenUserinfoAssertion');
return this.oidcTokenForm.get('idTokenUserinfoAssertion');
}
public get clockSkewSeconds(): AbstractControl | null {
return this.oidcForm.get('clockSkewSeconds');
return this.oidcTokenForm.get('clockSkewSeconds');
}
}
@@ -0,0 +1,31 @@
<h1 mat-dialog-title>
<span>{{ 'USER.CODEDIALOG.TITLE' | translate }} {{ data?.number }}</span>
</h1>
<p class="desc cnsl-secondary-text">{{ 'USER.CODEDIALOG.DESCRIPTION' | translate }}</p>
<div mat-dialog-content>
<cnsl-auth-method-radio
[authMethods]="data.authMethods"
[selected]="data.initialAuthMethod"
[current]="data.currentAuthMethod"
[isOIDC]="data.isOIDC"
(selectedMethod)="authmethod = $event"
[compact]="true"
>
</cnsl-auth-method-radio>
</div>
<div mat-dialog-actions class="action">
<button color="primary" mat-stroked-button class="ok-button" (click)="closeDialog()">
{{ 'ACTIONS.CLOSE' | translate }}
</button>
<button
[disabled]="!authmethod"
cdkFocusInitial
color="primary"
mat-raised-button
class="ok-button"
(click)="closeDialogWithMethod()"
>
{{ 'ACTIONS.SELECT' | translate }}
</button>
</div>
@@ -0,0 +1,25 @@
h1 {
font-size: 1.5rem;
margin: 0;
}
.desc {
font-size: 14px;
}
.formfield {
width: 100%;
}
.action {
display: flex;
justify-content: flex-end;
.ok-button {
margin-left: 0.5rem;
}
button {
border-radius: 0.5rem;
}
}
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AuthMethodDialogComponent } from './auth-method-dialog.component';
describe('AuthMethodDialogComponent', () => {
let component: AuthMethodDialogComponent;
let fixture: ComponentFixture<AuthMethodDialogComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [AuthMethodDialogComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AuthMethodDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,22 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
@Component({
selector: 'cnsl-auth-method-dialog',
templateUrl: './auth-method-dialog.component.html',
styleUrls: ['./auth-method-dialog.component.scss'],
})
export class AuthMethodDialogComponent {
public authmethod: string = '';
constructor(public dialogRef: MatDialogRef<AuthMethodDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {
this.authmethod = data.initialAuthMethod;
}
public closeDialog(): void {
this.dialogRef.close();
}
public closeDialogWithMethod(): void {
this.dialogRef.close(this.authmethod);
}
}
@@ -23,10 +23,10 @@ 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 { ClientKeysModule } from 'src/app/modules/client-keys/client-keys.module';
import { CreateLayoutModule } from 'src/app/modules/create-layout/create-layout.module';
import { InfoRowModule } from 'src/app/modules/info-row/info-row.module';
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
import { InputModule } from 'src/app/modules/input/input.module';
import { LinksModule } from 'src/app/modules/links/links.module';
import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
import { NameDialogModule } from 'src/app/modules/name-dialog/name-dialog.module';
import { SidenavModule } from 'src/app/modules/sidenav/sidenav.module';
@@ -38,6 +38,7 @@ import { RedirectPipeModule } from 'src/app/pipes/redirect-pipe/redirect-pipe.mo
import { AdditionalOriginsComponent } from './additional-origins/additional-origins.component';
import { AppCreateComponent } from './app-create/app-create.component';
import { AppDetailComponent } from './app-detail/app-detail.component';
import { AuthMethodDialogComponent } from './app-detail/auth-method-dialog/auth-method-dialog.component';
import { AppSecretDialogComponent } from './app-secret-dialog/app-secret-dialog.component';
import { AppsRoutingModule } from './apps-routing.module';
import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component';
@@ -49,12 +50,12 @@ import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component';
AppSecretDialogComponent,
RedirectUrisComponent,
AdditionalOriginsComponent,
AuthMethodDialogComponent,
],
imports: [
CommonModule,
A11yModule,
RedirectPipeModule,
LinksModule,
NameDialogModule,
AppRadioModule,
AppsRoutingModule,
@@ -66,6 +67,7 @@ import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component';
HasRoleModule,
SidenavModule,
MatChipsModule,
CreateLayoutModule,
ClientKeysModule,
HasRolePipeModule,
MatIconModule,