mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-06 13:07:52 +00:00
feat(console, login): v2 notification settings, login avatar (#3606)
* instance routing * instance naming * org list * rm isonsystem * breadcrumb type * routing * instance members * fragment refresh org * settings pages * settings list, sidenav grouping, i18n * org-settings, policy changes * lint * grid * rename grid * fallback to general * cleanup * general settings, remove cards * sidenav for settings, label policy * i18n * header, nav backbuild * general, project nav rehaul * login text background adapt * org nav anim * org, instance settings, fix policy layout, roles * i18n, active route for project * lint * notification-settings * idp create redirect, sms provider create, i18n * oidc configuration * settings list * new avatar colors for login * cleaner js * avatar theme login * remove avatar elevation
This commit is contained in:
parent
06e3330d2e
commit
d431ccb965
@ -1,6 +1,6 @@
|
||||
.card {
|
||||
margin: 1rem 0;
|
||||
padding: 1.5rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
padding-top: 1rem;
|
||||
min-width: 300px;
|
||||
|
@ -1,156 +1,179 @@
|
||||
<div class="container">
|
||||
<div class="abort-container">
|
||||
<button (click)="close()" mat-icon-button>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<span class="abort">{{ 'IDP.CREATE.TITLE' | translate }}</span><span class="abort-2">Step
|
||||
{{ currentCreateStep }} of
|
||||
{{ createSteps }}</span>
|
||||
</div>
|
||||
|
||||
<h1>{{'IDP.CREATE.TITLE' | translate}}</h1>
|
||||
|
||||
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<p class="desc cnsl-secondary-text">{{'IDP.CREATE.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<cnsl-idp-type-radio [types]="idpTypes" (selectedType)="idpType = $event" [selected]="idpType">
|
||||
</cnsl-idp-type-radio>
|
||||
|
||||
<div class="actions">
|
||||
<button mat-raised-button [disabled]="!idpType" color="primary"
|
||||
(click)="currentCreateStep = 2">{{'ACTIONS.CONTINUE' | translate}}</button>
|
||||
<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">{{ 'IDP.CREATE.TITLE' | translate }}</span
|
||||
><span class="abort-2">Step {{ currentCreateStep }} of {{ createSteps }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 2 && idpType === OIDC">
|
||||
<p class="desc cnsl-secondary-text">{{'IDP.OIDC.DESCRIPTION' | translate}}</p>
|
||||
<div class="idp-create-content">
|
||||
<h1>{{ 'IDP.CREATE.TITLE' | translate }}</h1>
|
||||
|
||||
<form [formGroup]="oidcFormGroup" (ngSubmit)="addOIDCIdp()">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{'IDP.AUTOREGISTER_DESC' | translate}}</p>
|
||||
<mat-checkbox formControlName="autoRegister">
|
||||
{{'IDP.AUTOREGISTER' | translate}}
|
||||
</mat-checkbox>
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.CREATE.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<cnsl-idp-type-radio [types]="idpTypes" (selectedType)="idpType = $event" [selected]="idpType">
|
||||
</cnsl-idp-type-radio>
|
||||
|
||||
<div class="first-step-actions">
|
||||
<button mat-raised-button [disabled]="!idpType" color="primary" (click)="currentCreateStep = 2">
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
</ng-container>
|
||||
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection" *ngIf="scopesList">
|
||||
<mat-chip class="chip" *ngFor="let scope of scopesList.value" selectable="false" removable
|
||||
(removed)="removeScope(scope)">
|
||||
{{scope}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input cnslInput [matChipInputFor]="chipScopesList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true" (matChipInputTokenEnd)="addScope($event)">
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="idpDisplayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.'+field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<ng-container *ngIf="currentCreateStep === 2 && idpType === OIDC">
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.OIDC.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<div class="idp-create-actions">
|
||||
<button color="primary" (click)="currentCreateStep = 1" mat-stroked-button class="back-button" type="button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="oidcFormGroup.invalid"
|
||||
type="submit">
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
<form [formGroup]="oidcFormGroup" (ngSubmit)="addOIDCIdp()">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 2 && idpType === JWT">
|
||||
<p class="desc cnsl-secondary-text">{{'IDP.JWT.DESCRIPTION' | translate}}</p>
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{ 'IDP.AUTOREGISTER_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="autoRegister">
|
||||
{{ 'IDP.AUTOREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
|
||||
<form [formGroup]="jwtFormGroup" (ngSubmit)="addJWTIdp()">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.HEADERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtHeaderName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtIssuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection" *ngIf="scopesList">
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="idpDisplayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield" appearance="outline">
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{'IDP.AUTOREGISTER_DESC' | translate}}</p>
|
||||
<mat-checkbox formControlName="jwtAutoRegister">
|
||||
{{'IDP.AUTOREGISTER' | translate}}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
<div class="idp-create-actions">
|
||||
<button color="primary" (click)="currentCreateStep = 1" mat-stroked-button class="back-button" type="button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="oidcFormGroup.invalid"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtEndpoint" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtKeysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<ng-container *ngIf="currentCreateStep === 2 && idpType === JWT">
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.JWT.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<div class="idp-create-actions">
|
||||
<button color="primary" (click)="currentCreateStep = 1" mat-stroked-button class="back-button" type="button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="jwtFormGroup.invalid"
|
||||
type="submit">
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
<form [formGroup]="jwtFormGroup" (ngSubmit)="addJWTIdp()">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.HEADERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtHeaderName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtIssuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{ 'IDP.AUTOREGISTER_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="jwtAutoRegister">
|
||||
{{ 'IDP.AUTOREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtEndpoint" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtKeysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="idp-create-actions">
|
||||
<button color="primary" (click)="currentCreateStep = 1" mat-stroked-button class="back-button" type="button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="jwtFormGroup.invalid"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,75 +2,75 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 4rem 4rem 2rem 4rem;
|
||||
.abort-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
padding: 4rem 1rem 2rem 1rem;
|
||||
.abort {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.abort-container {
|
||||
.abort-2 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.add-line-btn {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.idp-create-content {
|
||||
padding: 0 0 0 72px;
|
||||
|
||||
.first-step-actions {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.auto-reg-info {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
.auto-reg-desc {
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.idp-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
margin: 0 -0.5rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.abort {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.abort-2 {
|
||||
font-size: 1.2rem;
|
||||
margin-left: 2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.add-line-btn {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.auto-reg-info {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
.auto-reg-desc {
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.idp-content {
|
||||
display: flex;
|
||||
margin: 0 -0.5rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.desc {
|
||||
flex-basis: 100%;
|
||||
margin: 0 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
margin: 0 0.5rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
.desc {
|
||||
flex-basis: 100%;
|
||||
margin: 0 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
margin: 0 0.5rem;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.idp-create-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 1rem;
|
||||
|
||||
button[mat-stroked-button] {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
button[mat-raised-button] {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.idp-create-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 1rem;
|
||||
|
||||
button[mat-stroked-button] {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
button[mat-raised-button] {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
@ -83,13 +83,12 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL,
|
||||
];
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.INSTANCE,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
@ -98,11 +97,12 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL,
|
||||
];
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@ -139,15 +139,16 @@ export class IdpCreateComponent implements OnInit, OnDestroy {
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate([
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org'
|
||||
: this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam'
|
||||
: '',
|
||||
'policy',
|
||||
'login',
|
||||
]);
|
||||
this.router.navigate(
|
||||
[
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? '/org-settings'
|
||||
: this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? '/settings'
|
||||
: '',
|
||||
],
|
||||
{ queryParams: { id: 'idp' } },
|
||||
);
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -1,20 +1,33 @@
|
||||
<cnsl-top-view title="{{'IDP.DETAIL.TITLE' | translate}}"
|
||||
<cnsl-top-view
|
||||
title="{{ 'IDP.DETAIL.TITLE' | translate }}"
|
||||
[sub]="idp?.oidcConfig ? ('IDP.OIDC.TITLE' | translate) : idp?.jwtConfig ? ('IDP.JWT.TITLE' | translate) : ''"
|
||||
[isActive]="idp?.state === IDPState.IDP_STATE_ACTIVE" [isInactive]="idp?.state === IDPState.IDP_STATE_INACTIVE"
|
||||
[hasContributors]="false" stateTooltip="{{'IDP.STATES.'+idp?.state | translate}}"
|
||||
[hasActions]="(serviceType === PolicyComponentServiceType.MGMT ? ['org.idp.write'] : ['iam.idp.write']) | hasRole | async">
|
||||
<ng-template topActions cnslHasRole
|
||||
[hasRole]="serviceType === PolicyComponentServiceType.MGMT ? ['org.idp.write'] : ['iam.idp.write']">
|
||||
<button mat-menu-item *ngIf="idp?.state !== IDPState.IDP_STATE_INACTIVE"
|
||||
(click)="changeState(IDPState.IDP_STATE_INACTIVE)">
|
||||
{{'ACTIONS.DEACTIVATE' | translate}}
|
||||
[isActive]="idp?.state === IDPState.IDP_STATE_ACTIVE"
|
||||
[isInactive]="idp?.state === IDPState.IDP_STATE_INACTIVE"
|
||||
[hasContributors]="false"
|
||||
stateTooltip="{{ 'IDP.STATES.' + idp?.state | translate }}"
|
||||
[hasActions]="(serviceType === PolicyComponentServiceType.MGMT ? ['org.idp.write'] : ['iam.idp.write']) | hasRole | async"
|
||||
>
|
||||
<ng-template
|
||||
topActions
|
||||
cnslHasRole
|
||||
[hasRole]="serviceType === PolicyComponentServiceType.MGMT ? ['org.idp.write'] : ['iam.idp.write']"
|
||||
>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="idp?.state !== IDPState.IDP_STATE_INACTIVE"
|
||||
(click)="changeState(IDPState.IDP_STATE_INACTIVE)"
|
||||
>
|
||||
{{ 'ACTIONS.DEACTIVATE' | translate }}
|
||||
</button>
|
||||
<button mat-menu-item *ngIf="idp?.state === IDPState.IDP_STATE_INACTIVE"
|
||||
(click)="changeState(IDPState.IDP_STATE_ACTIVE)">
|
||||
{{'ACTIONS.REACTIVATE' | translate}}
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="idp?.state === IDPState.IDP_STATE_INACTIVE"
|
||||
(click)="changeState(IDPState.IDP_STATE_ACTIVE)"
|
||||
>
|
||||
{{ 'ACTIONS.REACTIVATE' | translate }}
|
||||
</button>
|
||||
<button mat-menu-item matTooltip="{{'IDP.DELETE' | translate}}" (click)="deleteIdp()">
|
||||
<span [style.color]="'var(--warn)'">{{'IDP.DELETE_TITLE' | translate}}</span>
|
||||
<button mat-menu-item matTooltip="{{ 'IDP.DELETE' | translate }}" (click)="deleteIdp()">
|
||||
<span [style.color]="'var(--warn)'">{{ 'IDP.DELETE_TITLE' | translate }}</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
<cnsl-info-row topContent *ngIf="idp" [idp]="idp"></cnsl-info-row>
|
||||
@ -24,8 +37,7 @@
|
||||
<form class="idp-form" (ngSubmit)="updateIdp()">
|
||||
<ng-container [formGroup]="idpForm">
|
||||
<div class="idp-content">
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
@ -33,16 +45,16 @@
|
||||
<cnsl-label>{{ 'IDP.STYLE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="stylingType">
|
||||
<mat-option *ngFor="let field of styleFields" [value]="field">
|
||||
{{ 'IDP.STYLEFIELD.'+field | translate }}
|
||||
{{ 'IDP.STYLEFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{'IDP.AUTOREGISTER_DESC' | translate}}</p>
|
||||
<p class="auto-reg-desc">{{ 'IDP.AUTOREGISTER_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="autoRegister" [disabled]="(canWrite | async) === false">
|
||||
{{'IDP.AUTOREGISTER' | translate}}
|
||||
{{ 'IDP.AUTOREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
@ -50,52 +62,72 @@
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button color="primary" mat-raised-button class="continue-button"
|
||||
[disabled]="idpForm.invalid || (canWrite | async) === false" type="submit">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="idpForm.invalid || (canWrite | async) === false"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<ng-container *ngIf="idp?.oidcConfig && oidcConfigForm">
|
||||
<h2>{{'IDP.OIDC.TITLE' | translate}}</h2>
|
||||
<p class="idp-desc cnsl-secondary-text">{{'IDP.OIDC.DESCRIPTION' | translate}}</p>
|
||||
<h2>{{ 'IDP.OIDC.TITLE' | translate }}</h2>
|
||||
<p class="idp-desc cnsl-secondary-text">{{ 'IDP.OIDC.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form (ngSubmit)="updateOidcConfig()">
|
||||
<ng-container [formGroup]="oidcConfigForm">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
<mat-checkbox class="idp-desc cnsl-secondary-text" [(ngModel)]="showIdSecretSection"
|
||||
[disabled]="(canWrite | async) === false" [ngModelOptions]="{standalone: true}">
|
||||
<mat-checkbox
|
||||
class="idp-desc cnsl-secondary-text"
|
||||
[(ngModel)]="showIdSecretSection"
|
||||
[disabled]="(canWrite | async) === false"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>
|
||||
Update Client Secret
|
||||
</mat-checkbox>
|
||||
<cnsl-form-field appearance="outline" class="formfield" *ngIf="showIdSecretSection">
|
||||
<cnsl-form-field class="formfield" *ngIf="showIdSecretSection">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
<div class="line">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
|
||||
<input cnslInput [matChipInputFor]="chipScopesList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true" (matChipInputTokenEnd)="addScope($event)">
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
<button (click)="addScope($any($event))" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<cnsl-form-field appearance="outline" class="formfield fullwidth">
|
||||
<cnsl-form-field class="formfield fullwidth">
|
||||
<mat-chip-list class="chip-list" #chipScopesList aria-label="scope selection">
|
||||
<mat-chip class="chip" *ngFor="let scope of scopesList?.value" selectable="false" removable
|
||||
(removed)="removeScope(scope)" [disabled]="(canWrite | async) === false">
|
||||
{{scope}} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList?.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
[disabled]="(canWrite | async) === false"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
@ -104,7 +136,7 @@
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="displayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.'+field | translate }}
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
@ -112,7 +144,7 @@
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.'+field | translate }}
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
@ -120,8 +152,13 @@
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button color="primary" mat-raised-button class="continue-button"
|
||||
[disabled]="oidcConfigForm.invalid || (canWrite | async) === false" type="submit">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="oidcConfigForm.invalid || (canWrite | async) === false"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
@ -129,28 +166,28 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="idp?.jwtConfig && jwtConfigForm">
|
||||
<h2>{{'IDP.JWT.TITLE' | translate}}</h2>
|
||||
<p>{{'IDP.JWT.DESCRIPTION' | translate}}</p>
|
||||
<h2>{{ 'IDP.JWT.TITLE' | translate }}</h2>
|
||||
<p>{{ 'IDP.JWT.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form (ngSubmit)="updateJwtConfig()">
|
||||
<ng-container [formGroup]="jwtConfigForm">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.HEADERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="headerName" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field appearance="outline" class="formfield">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="keysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
@ -158,11 +195,16 @@
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button color="primary" mat-raised-button class="continue-button"
|
||||
[disabled]="jwtConfigForm.invalid || (canWrite | async) === false" type="submit">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="jwtConfigForm.invalid || (canWrite | async) === false"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@
|
||||
.general-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 1rem;
|
||||
|
||||
.save-button {
|
||||
display: block;
|
||||
|
@ -1,55 +1,35 @@
|
||||
import { Component, Injector, Input, OnInit, Type } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { SetDefaultLanguageResponse } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-general-settings',
|
||||
templateUrl: './general-settings.component.html',
|
||||
styleUrls: ['./general-settings.component.scss'],
|
||||
})
|
||||
export class GeneralSettingsComponent implements OnInit {
|
||||
@Input() public serviceType!: PolicyComponentServiceType;
|
||||
public service!: ManagementService | AdminService;
|
||||
|
||||
public defaultLanguage: string = '';
|
||||
public defaultLanguageOptions: string[] = [];
|
||||
|
||||
public loading: boolean = false;
|
||||
constructor(private injector: Injector, private toast: ToastService) {}
|
||||
constructor(private service: AdminService, private toast: ToastService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
break;
|
||||
}
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
private fetchData(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
(this.service as AdminService).getDefaultLanguage().then((langResp) => {
|
||||
this.defaultLanguage = langResp.language;
|
||||
});
|
||||
(this.service as AdminService).getSupportedLanguages().then((supportedResp) => {
|
||||
this.defaultLanguageOptions = supportedResp.languagesList;
|
||||
});
|
||||
}
|
||||
this.service.getDefaultLanguage().then((langResp) => {
|
||||
this.defaultLanguage = langResp.language;
|
||||
});
|
||||
this.service.getSupportedLanguages().then((supportedResp) => {
|
||||
this.defaultLanguageOptions = supportedResp.languagesList;
|
||||
});
|
||||
}
|
||||
|
||||
private updateData(): Promise<SetDefaultLanguageResponse.AsObject> | void {
|
||||
if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
return (this.service as AdminService).setDefaultLanguage(this.defaultLanguage);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
private updateData(): Promise<SetDefaultLanguageResponse.AsObject> {
|
||||
return (this.service as AdminService).setDefaultLanguage(this.defaultLanguage);
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
@ -68,21 +48,4 @@ export class GeneralSettingsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public removePolicy(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
(this.service as ManagementService)
|
||||
.resetLoginPolicyToDefault()
|
||||
.then(() => {
|
||||
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
|
||||
this.loading = true;
|
||||
setTimeout(() => {
|
||||
this.fetchData();
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
margin-left: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
<div class="mfa-list-btns">
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="primary"
|
||||
class="new-mfa cnsl-action-button"
|
||||
[disabled]="disabled"
|
||||
(click)="!disabled ? addMfa() : null"
|
||||
|
@ -0,0 +1,48 @@
|
||||
<h1 mat-dialog-title class="title">
|
||||
<span>{{ 'SETTING.SMS.ADDPROVIDER' | translate }}</span>
|
||||
</h1>
|
||||
<div mat-dialog-content>
|
||||
<p class="desc cnsl-secondary-text">{{ 'SETTING.SMS.ADDPROVIDERDESCRIPTION' | translate }}</p>
|
||||
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
<cnsl-label>{{ 'MFA.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="provider">
|
||||
<mat-option *ngFor="let prov of availableSMSProviders" [value]="prov">
|
||||
<span *ngIf="prov === SMSProviderType.Twilio">Twilio</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<form *ngIf="provider === SMSProviderType.Twilio" (ngSubmit)="closeDialogWithRequest()" [formGroup]="twilioForm">
|
||||
<h2>Twilio</h2>
|
||||
|
||||
<cnsl-form-field class="sms-form-field" label="sid">
|
||||
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SID' | translate }}</cnsl-label>
|
||||
<input cnslInput name="sid" formControlName="sid" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="sms-form-field" label="Token">
|
||||
<cnsl-label>{{ 'SETTING.SMS.TWILIO.TOKEN' | translate }}</cnsl-label>
|
||||
<input cnslInput name="token" formControlName="token" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="sms-form-field" label="Sender Number">
|
||||
<cnsl-label>{{ 'SETTING.SMS.TWILIO.SENDERNUMBER' | translate }}</cnsl-label>
|
||||
<input cnslInput name="senderNumber" formControlName="senderNumber" />
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-stroked-button (click)="closeDialog()">
|
||||
<span>{{ 'ACTIONS.CLOSE' | translate }}</span>
|
||||
</button>
|
||||
<button
|
||||
[disabled]="provider === SMSProviderType.Twilio && !twilioForm.valid"
|
||||
mat-raised-button
|
||||
class="ok-button"
|
||||
color="primary"
|
||||
(click)="closeDialogWithRequest()"
|
||||
>
|
||||
<span>{{ 'ACTIONS.OK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,20 @@
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { AddSMSProviderTwilioRequest } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
|
||||
enum SMSProviderType {
|
||||
Twilio = 1,
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-dialog-add-sms-provider',
|
||||
templateUrl: './dialog-add-sms-provider.component.html',
|
||||
styleUrls: ['./dialog-add-sms-provider.component.scss'],
|
||||
})
|
||||
export class DialogAddSMSProviderComponent {
|
||||
public SMSProviderType: any = SMSProviderType;
|
||||
public availableSMSProviders: SMSProviderType[] = [SMSProviderType.Twilio];
|
||||
public provider: SMSProviderType = SMSProviderType.Twilio;
|
||||
public req: AddSMSProviderTwilioRequest = new AddSMSProviderTwilioRequest();
|
||||
|
||||
public twilioForm!: FormGroup;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
public dialogRef: MatDialogRef<DialogAddSMSProviderComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
) {
|
||||
this.twilioForm = this.fb.group({
|
||||
sid: ['', [Validators.required]],
|
||||
token: ['', [Validators.required]],
|
||||
senderNumber: ['', [Validators.required]],
|
||||
});
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
public closeDialogWithRequest(): void {
|
||||
this.req.setSid(this.sid?.value);
|
||||
this.req.setToken(this.token?.value);
|
||||
this.req.setSenderNumber(this.senderNumber?.value);
|
||||
|
||||
this.dialogRef.close(this.req);
|
||||
}
|
||||
|
||||
public get senderNumber(): AbstractControl | null {
|
||||
return this.twilioForm.get('senderNumber');
|
||||
}
|
||||
|
||||
public get token(): AbstractControl | null {
|
||||
return this.twilioForm.get('token');
|
||||
}
|
||||
|
||||
public get sid(): AbstractControl | null {
|
||||
return this.twilioForm.get('sid');
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
<div class="spinner-wr">
|
||||
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<h2>{{ 'SETTING.SMTP.TITLE' | translate }}</h2>
|
||||
|
||||
<form (ngSubmit)="savePolicy()" [formGroup]="form" autocomplete="off">
|
||||
<cnsl-form-field class="smtp-form-field" label="Sender Address" required="true">
|
||||
<cnsl-label>{{ 'SETTING.SMTP.SENDERADDRESS' | translate }}</cnsl-label>
|
||||
<input cnslInput name="senderAddress" formControlName="senderAddress" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="smtp-form-field" label="Sender Name" required="true">
|
||||
<cnsl-label>{{ 'SETTING.SMTP.SENDERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput name="senderName" formControlName="senderName" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox class="smtp-checkbox" formControlName="tls">
|
||||
{{ 'SETTING.SMTP.TLS' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<cnsl-form-field class="smtp-form-field" label="Host" required="true">
|
||||
<cnsl-label>{{ 'SETTING.SMTP.HOST' | translate }}</cnsl-label>
|
||||
<input cnslInput name="host" formControlName="host" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="smtp-form-field" label="User" required="true">
|
||||
<cnsl-label>{{ 'SETTING.SMTP.USER' | translate }}</cnsl-label>
|
||||
<input id="smtp-user" cnslInput name="smtp-user" autocomplete="smtp-user" formControlName="user" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="smtp-form-field" label="Password" required="true">
|
||||
<cnsl-label>{{ 'SETTING.SMTP.PASSWORD' | translate }}</cnsl-label>
|
||||
<input
|
||||
id="smtp-password"
|
||||
cnslInput
|
||||
name="smtp-password"
|
||||
autocomplete="smtp-password"
|
||||
type="password"
|
||||
formControlName="password"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="general-btn-container">
|
||||
<button class="save-button" (click)="savePolicy()" color="primary" type="submit" mat-raised-button>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<br />
|
||||
<h2>{{ 'SETTING.SMS.TITLE' | translate }}</h2>
|
||||
<h3>{{ 'SETTING.SMS.PROVIDERS' | translate }}</h3>
|
||||
<div class="sms-providers">
|
||||
<cnsl-card *ngFor="let provider of smsProviders" class="sms-card">
|
||||
<div *ngIf="provider.twilio" class="sms-provider">
|
||||
<h4 class="title">Twilio</h4>
|
||||
<span class="cnsl-secondary-text">{{ 'SETTING.SMS.PROVIDER' | translate }}</span>
|
||||
|
||||
<span
|
||||
class="state"
|
||||
[ngClass]="{
|
||||
active: provider.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_ACTIVE,
|
||||
inactive: provider.state === SMSProviderConfigState.SMS_PROVIDER_CONFIG_INACTIVE
|
||||
}"
|
||||
></span>
|
||||
</div>
|
||||
</cnsl-card>
|
||||
<button mat-stroked-button (click)="addSMSProvider()">
|
||||
<div class="sms-card add">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>{{ 'ACTIONS.ADD' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,55 @@
|
||||
.spinner-wr {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.smtp-form-field {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.smtp-checkbox {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.general-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
|
||||
.save-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.sms-providers {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.sms-card {
|
||||
margin-right: 1rem;
|
||||
|
||||
&.add {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sms-provider {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: -0.5rem;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NotificationSettingsComponent } from './notification-settings.component';
|
||||
|
||||
describe('NotificationSettingsComponent', () => {
|
||||
let component: NotificationSettingsComponent;
|
||||
let fixture: ComponentFixture<NotificationSettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [NotificationSettingsComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NotificationSettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,158 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {
|
||||
AddSMSProviderTwilioRequest,
|
||||
UpdateSMTPConfigPasswordResponse,
|
||||
UpdateSMTPConfigRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { SMSProvider, SMSProviderConfigState } from 'src/app/proto/generated/zitadel/settings_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-notification-settings',
|
||||
templateUrl: './notification-settings.component.html',
|
||||
styleUrls: ['./notification-settings.component.scss'],
|
||||
})
|
||||
export class NotificationSettingsComponent implements OnInit {
|
||||
@Input() public serviceType!: PolicyComponentServiceType;
|
||||
public smsProviders: SMSProvider.AsObject[] = [];
|
||||
|
||||
public loading: boolean = false;
|
||||
public form!: FormGroup;
|
||||
|
||||
public SMSProviderConfigState: any = SMSProviderConfigState;
|
||||
constructor(
|
||||
private service: AdminService,
|
||||
private dialog: MatDialog,
|
||||
private toast: ToastService,
|
||||
private fb: FormBuilder,
|
||||
) {
|
||||
this.form = this.fb.group({
|
||||
senderAddress: ['', [Validators.required]],
|
||||
senderName: ['', [Validators.required]],
|
||||
tls: [true, [Validators.required]],
|
||||
host: ['', [Validators.required]],
|
||||
user: ['', [Validators.required]],
|
||||
password: ['', [Validators.required]],
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
private fetchData(): void {
|
||||
this.service
|
||||
.getSMTPConfig()
|
||||
.then((smtpConfig) => {
|
||||
if (smtpConfig.smtpConfig) {
|
||||
this.form.patchValue(smtpConfig.smtpConfig);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error && error.code === 5) {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
|
||||
this.service.listSMSProviders().then((smsProviders) => {
|
||||
if (smsProviders.resultList) {
|
||||
this.smsProviders = smsProviders.resultList;
|
||||
console.log(this.smsProviders);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateData(): Promise<UpdateSMTPConfigPasswordResponse.AsObject> | any {
|
||||
const req = new UpdateSMTPConfigRequest();
|
||||
req.setHost(this.host?.value ?? '');
|
||||
req.setSenderAddress(this.senderAddress?.value ?? '');
|
||||
req.setSenderName(this.senderName?.value ?? '');
|
||||
req.setTls(this.tls?.value ?? false);
|
||||
req.setUser(this.user?.value ?? '');
|
||||
|
||||
console.log(req.toObject());
|
||||
|
||||
// return this.service.updateSMTPConfig(req).then(() => {
|
||||
// let passwordReq: UpdateSMTPConfigPasswordRequest;
|
||||
// if (this.password) {
|
||||
// passwordReq = new UpdateSMTPConfigPasswordRequest();
|
||||
// passwordReq.setPassword(this.password.value);
|
||||
// return this.service.updateSMTPConfigPassword(passwordReq);
|
||||
// } else {
|
||||
// return;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
const prom = this.updateData();
|
||||
if (prom) {
|
||||
prom
|
||||
.then(() => {
|
||||
this.toast.showInfo('SETTING.SMTP.SAVED', true);
|
||||
this.loading = true;
|
||||
setTimeout(() => {
|
||||
this.fetchData();
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public addSMSProvider(): void {
|
||||
const dialogRef = this.dialog.open(DialogAddSMSProviderComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'IDP.DELETE_TITLE',
|
||||
descriptionKey: 'IDP.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((req: AddSMSProviderTwilioRequest) => {
|
||||
if (req) {
|
||||
this.service
|
||||
.addSMSProviderTwilio(req)
|
||||
.then(() => {
|
||||
this.toast.showInfo('SETTING.SMS.TWILIO.ADDED', true);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public get senderAddress(): AbstractControl | null {
|
||||
return this.form.get('senderAddress');
|
||||
}
|
||||
|
||||
public get senderName(): AbstractControl | null {
|
||||
return this.form.get('senderName');
|
||||
}
|
||||
|
||||
public get tls(): AbstractControl | null {
|
||||
return this.form.get('tls');
|
||||
}
|
||||
|
||||
public get user(): AbstractControl | null {
|
||||
return this.form.get('user');
|
||||
}
|
||||
|
||||
public get host(): AbstractControl | null {
|
||||
return this.form.get('host');
|
||||
}
|
||||
|
||||
public get password(): AbstractControl | null {
|
||||
return this.form.get('password');
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { FormFieldModule } from '../../form-field/form-field.module';
|
||||
import { InputModule } from '../../input/input.module';
|
||||
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
|
||||
import { NotificationSettingsComponent } from './notification-settings.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [NotificationSettingsComponent, DialogAddSMSProviderComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
InputModule,
|
||||
MatIconModule,
|
||||
FormFieldModule,
|
||||
MatSelectModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSelectModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [NotificationSettingsComponent],
|
||||
})
|
||||
export class NotificationSettingsModule {}
|
@ -0,0 +1,45 @@
|
||||
<div class="spinner-wr">
|
||||
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
<h2>{{ 'SETTING.OIDC.TITLE' | translate }}</h2>
|
||||
<form (ngSubmit)="savePolicy()" [formGroup]="form" autocomplete="off">
|
||||
<cnsl-form-field class="oidc-form-field" label="Sender Address" required="true">
|
||||
<cnsl-label
|
||||
>{{ 'SETTING.OIDC.ACCESSTOKENLIFETIME' | translate }} <strong
|
||||
>({{ 'SETTING.OIDC.INHOURS' | translate }})</strong
|
||||
></cnsl-label
|
||||
>
|
||||
<input cnslInput type="number" name="accessTokenLifetime" formControlName="accessTokenLifetime" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="oidc-form-field" label="Sender Name" required="true">
|
||||
<cnsl-label
|
||||
>{{ 'SETTING.OIDC.IDTOKENLIFETIME' | translate }} <strong
|
||||
>({{ 'SETTING.OIDC.INHOURS' | translate }})</strong
|
||||
></cnsl-label
|
||||
>
|
||||
<input cnslInput type="number" name="idTokenLifetime" formControlName="idTokenLifetime" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="oidc-form-field" label="Sender Address" required="true">
|
||||
<cnsl-label
|
||||
>{{ 'SETTING.OIDC.REFRESHTOKENEXPIRATION' | translate }} <strong
|
||||
>({{ 'SETTING.OIDC.INDAYS' | translate }})</strong
|
||||
></cnsl-label
|
||||
>
|
||||
<input cnslInput type="number" name="refreshTokenExpiration" formControlName="refreshTokenExpiration" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="oidc-form-field" label="Sender Name" required="true">
|
||||
<cnsl-label
|
||||
>{{ 'SETTING.OIDC.REFRESHTOKENIDLEEXPIRATION' | translate }}
|
||||
<strong>({{ 'SETTING.OIDC.INDAYS' | translate }})</strong></cnsl-label
|
||||
>
|
||||
<input cnslInput type="number" name="refreshTokenIdleExpiration" formControlName="refreshTokenIdleExpiration" />
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
<div class="oidc-btn-container">
|
||||
<button class="save-button" (click)="savePolicy()" color="primary" type="submit" mat-raised-button>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,18 @@
|
||||
.spinner-wr {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.oidc-form-field {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.oidc-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 1rem;
|
||||
|
||||
.save-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { OIDCConfigurationComponent } from './oidc-configuration.component';
|
||||
|
||||
describe('OIDCConfigurationComponent', () => {
|
||||
let component: OIDCConfigurationComponent;
|
||||
let fixture: ComponentFixture<OIDCConfigurationComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [OIDCConfigurationComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(OIDCConfigurationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,119 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
|
||||
import { SetDefaultLanguageResponse, UpdateOIDCSettingsRequest } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { OIDCSettings } from 'src/app/proto/generated/zitadel/settings_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-oidc-configuration',
|
||||
templateUrl: './oidc-configuration.component.html',
|
||||
styleUrls: ['./oidc-configuration.component.scss'],
|
||||
})
|
||||
export class OIDCConfigurationComponent implements OnInit {
|
||||
public oidcSettings!: OIDCSettings.AsObject;
|
||||
|
||||
public loading: boolean = false;
|
||||
public form!: FormGroup;
|
||||
constructor(private service: AdminService, private fb: FormBuilder, private toast: ToastService) {
|
||||
this.form = this.fb.group({
|
||||
accessTokenLifetime: [12, [Validators.required]],
|
||||
idTokenLifetime: [12, [Validators.required]],
|
||||
refreshTokenExpiration: [30, [Validators.required]],
|
||||
refreshTokenIdleExpiration: [90, [Validators.required]],
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
private fetchData(): void {
|
||||
this.service
|
||||
.getOIDCSettings()
|
||||
.then((oidcConfiguration) => {
|
||||
if (oidcConfiguration.settings) {
|
||||
this.oidcSettings = oidcConfiguration.settings;
|
||||
|
||||
this.accessTokenLifetime?.setValue(
|
||||
oidcConfiguration.settings.accessTokenLifetime?.seconds
|
||||
? oidcConfiguration.settings.accessTokenLifetime?.seconds / 60 / 60
|
||||
: 12,
|
||||
);
|
||||
this.idTokenLifetime?.setValue(
|
||||
oidcConfiguration.settings.idTokenLifetime?.seconds
|
||||
? oidcConfiguration.settings.idTokenLifetime?.seconds / 60 / 60
|
||||
: 12,
|
||||
);
|
||||
this.refreshTokenExpiration?.setValue(
|
||||
oidcConfiguration.settings.refreshTokenExpiration?.seconds
|
||||
? oidcConfiguration.settings.refreshTokenExpiration?.seconds / 60 / 60 / 24
|
||||
: 30,
|
||||
);
|
||||
this.refreshTokenIdleExpiration?.setValue(
|
||||
oidcConfiguration.settings.refreshTokenIdleExpiration?.seconds
|
||||
? oidcConfiguration.settings.refreshTokenIdleExpiration?.seconds / 60 / 60 / 24
|
||||
: 90,
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.code === 5) {
|
||||
} else {
|
||||
this.toast.showError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateData(): Promise<SetDefaultLanguageResponse.AsObject> {
|
||||
const req = new UpdateOIDCSettingsRequest();
|
||||
|
||||
const accessToken = new Duration().setSeconds((this.accessTokenLifetime?.value ?? 12) * 60 * 60);
|
||||
req.setAccessTokenLifetime(accessToken);
|
||||
|
||||
const idToken = new Duration().setSeconds((this.idTokenLifetime?.value ?? 12) * 60 * 60);
|
||||
req.setIdTokenLifetime(idToken);
|
||||
|
||||
const refreshToken = new Duration().setSeconds((this.refreshTokenExpiration?.value ?? 30) * 60 * 60 * 24);
|
||||
req.setRefreshTokenExpiration(refreshToken);
|
||||
|
||||
const refreshIdleToken = new Duration().setSeconds((this.refreshTokenIdleExpiration?.value ?? 90) * 60 * 60 * 24);
|
||||
req.setRefreshTokenIdleExpiration(refreshIdleToken);
|
||||
|
||||
return (this.service as AdminService).updateOIDCSettings(req);
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
const prom = this.updateData();
|
||||
if (prom) {
|
||||
prom
|
||||
.then(() => {
|
||||
this.toast.showInfo('SETTING.SMTP.SAVED', true);
|
||||
this.loading = true;
|
||||
setTimeout(() => {
|
||||
this.fetchData();
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public get accessTokenLifetime(): AbstractControl | null {
|
||||
return this.form.get('accessTokenLifetime');
|
||||
}
|
||||
|
||||
public get idTokenLifetime(): AbstractControl | null {
|
||||
return this.form.get('idTokenLifetime');
|
||||
}
|
||||
|
||||
public get refreshTokenExpiration(): AbstractControl | null {
|
||||
return this.form.get('refreshTokenExpiration');
|
||||
}
|
||||
|
||||
public get refreshTokenIdleExpiration(): AbstractControl | null {
|
||||
return this.form.get('refreshTokenIdleExpiration');
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { FormFieldModule } from '../../form-field/form-field.module';
|
||||
import { InputModule } from '../../input/input.module';
|
||||
import { OIDCConfigurationComponent } from './oidc-configuration.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [OIDCConfigurationComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
FormsModule,
|
||||
MatButtonModule,
|
||||
FormFieldModule,
|
||||
ReactiveFormsModule,
|
||||
InputModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSelectModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [OIDCConfigurationComponent],
|
||||
})
|
||||
export class OIDCConfigurationModule {}
|
@ -42,9 +42,7 @@ export class PasswordLockoutPolicyComponent implements OnInit {
|
||||
}
|
||||
|
||||
private fetchData(): void {
|
||||
console.log(this.serviceType);
|
||||
this.getData().then((resp) => {
|
||||
console.log(resp);
|
||||
if (resp.policy) {
|
||||
this.lockoutData = resp.policy;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
queryParam="id"
|
||||
>
|
||||
<ng-container *ngIf="currentSetting === 'general' && serviceType === PolicyComponentServiceType.ADMIN">
|
||||
<cnsl-general-settings [serviceType]="serviceType"></cnsl-general-settings>
|
||||
<cnsl-general-settings></cnsl-general-settings>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="currentSetting === 'complexity'">
|
||||
<cnsl-password-complexity-policy [serviceType]="serviceType"></cnsl-password-complexity-policy>
|
||||
@ -22,6 +22,14 @@
|
||||
<ng-container *ngIf="currentSetting === 'idp'">
|
||||
<cnsl-idp-settings [serviceType]="serviceType"></cnsl-idp-settings>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="currentSetting === 'notifications' && serviceType === PolicyComponentServiceType.ADMIN">
|
||||
<cnsl-notification-settings [serviceType]="serviceType"></cnsl-notification-settings>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentSetting === 'oidc' && serviceType === PolicyComponentServiceType.ADMIN">
|
||||
<cnsl-oidc-configuration></cnsl-oidc-configuration>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentSetting === 'branding'">
|
||||
<cnsl-private-labeling-policy [serviceType]="serviceType"></cnsl-private-labeling-policy>
|
||||
</ng-container>
|
||||
|
@ -10,6 +10,8 @@ import { IdpSettingsModule } from '../policies/idp-settings/idp-settings.module'
|
||||
import { LoginPolicyModule } from '../policies/login-policy/login-policy.module';
|
||||
import { LoginTextsPolicyModule } from '../policies/login-texts/login-texts.module';
|
||||
import { MessageTextsPolicyModule } from '../policies/message-texts/message-texts.module';
|
||||
import { NotificationSettingsModule } from '../policies/notification-settings/notification-settings.module';
|
||||
import { OIDCConfigurationModule } from '../policies/oidc-configuration/oidc-configuration.module';
|
||||
import { OrgIamPolicyModule } from '../policies/org-iam-policy/org-iam-policy.module';
|
||||
import { PasswordComplexityPolicyModule } from '../policies/password-complexity-policy/password-complexity-policy.module';
|
||||
import { PasswordLockoutPolicyModule } from '../policies/password-lockout-policy/password-lockout-policy.module';
|
||||
@ -37,6 +39,8 @@ import { SettingsListComponent } from './settings-list.component';
|
||||
OrgIamPolicyModule,
|
||||
TranslateModule,
|
||||
HasRolePipeModule,
|
||||
NotificationSettingsModule,
|
||||
OIDCConfigurationModule,
|
||||
],
|
||||
exports: [SettingsListComponent],
|
||||
})
|
||||
|
@ -5,6 +5,11 @@ export const GENERAL: SidenavSetting = {
|
||||
i18nKey: 'SETTINGS.LIST.GENERAL',
|
||||
};
|
||||
|
||||
export const OIDC: SidenavSetting = {
|
||||
id: 'oidc',
|
||||
i18nKey: 'SETTINGS.LIST.OIDC',
|
||||
};
|
||||
|
||||
export const LOGIN: SidenavSetting = {
|
||||
id: 'login',
|
||||
i18nKey: 'SETTINGS.LIST.LOGIN',
|
||||
@ -29,12 +34,6 @@ export const COMPLEXITY: SidenavSetting = {
|
||||
|
||||
export const IDP: SidenavSetting = { id: 'idp', i18nKey: 'SETTINGS.LIST.IDP', groupI18nKey: 'SETTINGS.GROUPS.LOGIN' };
|
||||
|
||||
export const NOTIFICATIONPROVIDERS: SidenavSetting = {
|
||||
id: 'notificationproviders',
|
||||
i18nKey: 'SETTINGS.LIST.NOTIFICATIONPROVIDERS',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.NOTIFICATIONS',
|
||||
};
|
||||
|
||||
export const NOTIFICATIONS: SidenavSetting = {
|
||||
id: 'notifications',
|
||||
i18nKey: 'SETTINGS.LIST.NOTIFICATIONS',
|
||||
|
@ -14,8 +14,8 @@ import {
|
||||
LOGIN,
|
||||
LOGINTEXTS,
|
||||
MESSAGETEXTS,
|
||||
NOTIFICATIONPROVIDERS,
|
||||
NOTIFICATIONS,
|
||||
OIDC,
|
||||
PRIVACYPOLICY,
|
||||
} from '../../modules/settings-list/settings';
|
||||
|
||||
@ -29,16 +29,20 @@ export class InstanceSettingsComponent {
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
public settingsList: SidenavSetting[] = [
|
||||
GENERAL,
|
||||
// notifications
|
||||
NOTIFICATIONS,
|
||||
// login
|
||||
LOGIN,
|
||||
COMPLEXITY,
|
||||
LOCKOUT,
|
||||
IDP,
|
||||
NOTIFICATIONS,
|
||||
NOTIFICATIONPROVIDERS,
|
||||
// appearance
|
||||
BRANDING,
|
||||
MESSAGETEXTS,
|
||||
LOGINTEXTS,
|
||||
// others
|
||||
PRIVACYPOLICY,
|
||||
OIDC,
|
||||
];
|
||||
constructor(breadcrumbService: BreadcrumbService, activatedRoute: ActivatedRoute) {
|
||||
const breadcrumbs = [
|
||||
|
@ -13,8 +13,6 @@ import {
|
||||
LOGIN,
|
||||
LOGINTEXTS,
|
||||
MESSAGETEXTS,
|
||||
NOTIFICATIONPROVIDERS,
|
||||
NOTIFICATIONS,
|
||||
PRIVACYPOLICY,
|
||||
} from '../../modules/settings-list/settings';
|
||||
|
||||
@ -31,8 +29,6 @@ export class OrgSettingsComponent {
|
||||
COMPLEXITY,
|
||||
LOCKOUT,
|
||||
IDP,
|
||||
NOTIFICATIONS,
|
||||
NOTIFICATIONPROVIDERS,
|
||||
BRANDING,
|
||||
MESSAGETEXTS,
|
||||
LOGINTEXTS,
|
||||
|
@ -17,6 +17,8 @@ import {
|
||||
AddOIDCIDPResponse,
|
||||
AddSecondFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyResponse,
|
||||
AddSMSProviderTwilioRequest,
|
||||
AddSMSProviderTwilioResponse,
|
||||
DeactivateIDPRequest,
|
||||
DeactivateIDPResponse,
|
||||
GetCustomDomainClaimedMessageTextRequest,
|
||||
@ -51,6 +53,8 @@ import {
|
||||
GetDefaultVerifyEmailMessageTextResponse,
|
||||
GetDefaultVerifyPhoneMessageTextRequest,
|
||||
GetDefaultVerifyPhoneMessageTextResponse,
|
||||
GetFileSystemNotificationProviderRequest,
|
||||
GetFileSystemNotificationProviderResponse,
|
||||
GetIDPByIDRequest,
|
||||
GetIDPByIDResponse,
|
||||
GetLabelPolicyRequest,
|
||||
@ -59,6 +63,10 @@ import {
|
||||
GetLockoutPolicyResponse,
|
||||
GetLoginPolicyRequest,
|
||||
GetLoginPolicyResponse,
|
||||
GetLogNotificationProviderRequest,
|
||||
GetLogNotificationProviderResponse,
|
||||
GetOIDCSettingsRequest,
|
||||
GetOIDCSettingsResponse,
|
||||
GetOrgIAMPolicyRequest,
|
||||
GetOrgIAMPolicyResponse,
|
||||
GetPasswordAgePolicyRequest,
|
||||
@ -69,6 +77,10 @@ import {
|
||||
GetPreviewLabelPolicyResponse,
|
||||
GetPrivacyPolicyRequest,
|
||||
GetPrivacyPolicyResponse,
|
||||
GetSMSProviderRequest,
|
||||
GetSMSProviderResponse,
|
||||
GetSMTPConfigRequest,
|
||||
GetSMTPConfigResponse,
|
||||
GetSupportedLanguagesRequest,
|
||||
GetSupportedLanguagesResponse,
|
||||
IDPQuery,
|
||||
@ -86,6 +98,8 @@ import {
|
||||
ListLoginPolicyMultiFactorsResponse,
|
||||
ListLoginPolicySecondFactorsRequest,
|
||||
ListLoginPolicySecondFactorsResponse,
|
||||
ListSMSProvidersRequest,
|
||||
ListSMSProvidersResponse,
|
||||
ListViewsRequest,
|
||||
ListViewsResponse,
|
||||
ReactivateIDPRequest,
|
||||
@ -150,6 +164,8 @@ import {
|
||||
UpdateLockoutPolicyResponse,
|
||||
UpdateLoginPolicyRequest,
|
||||
UpdateLoginPolicyResponse,
|
||||
UpdateOIDCSettingsRequest,
|
||||
UpdateOIDCSettingsResponse,
|
||||
UpdateOrgIAMPolicyRequest,
|
||||
UpdateOrgIAMPolicyResponse,
|
||||
UpdatePasswordAgePolicyRequest,
|
||||
@ -158,6 +174,10 @@ import {
|
||||
UpdatePasswordComplexityPolicyResponse,
|
||||
UpdatePrivacyPolicyRequest,
|
||||
UpdatePrivacyPolicyResponse,
|
||||
UpdateSMTPConfigPasswordRequest,
|
||||
UpdateSMTPConfigPasswordResponse,
|
||||
UpdateSMTPConfigRequest,
|
||||
UpdateSMTPConfigResponse,
|
||||
} from '../proto/generated/zitadel/admin_pb';
|
||||
import { SearchQuery } from '../proto/generated/zitadel/member_pb';
|
||||
import { ListQuery } from '../proto/generated/zitadel/object_pb';
|
||||
@ -433,6 +453,37 @@ export class AdminService {
|
||||
return this.grpcService.admin.setDefaultLanguage(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* notification settings */
|
||||
|
||||
public getSMTPConfig(): Promise<GetSMTPConfigResponse.AsObject> {
|
||||
const req = new GetSMTPConfigRequest();
|
||||
return this.grpcService.admin.getSMTPConfig(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateSMTPConfig(req: UpdateSMTPConfigRequest): Promise<UpdateSMTPConfigResponse.AsObject> {
|
||||
return this.grpcService.admin.updateSMTPConfig(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateSMTPConfigPassword(req: UpdateSMTPConfigPasswordRequest): Promise<UpdateSMTPConfigPasswordResponse.AsObject> {
|
||||
return this.grpcService.admin.updateSMTPConfigPassword(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* sms */
|
||||
|
||||
public listSMSProviders(): Promise<ListSMSProvidersResponse.AsObject> {
|
||||
const req = new ListSMSProvidersRequest();
|
||||
return this.grpcService.admin.listSMSProviders(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getSMSProvider(): Promise<GetSMSProviderResponse.AsObject> {
|
||||
const req = new GetSMSProviderRequest();
|
||||
return this.grpcService.admin.getSMSProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addSMSProviderTwilio(req: AddSMSProviderTwilioRequest): Promise<AddSMSProviderTwilioResponse.AsObject> {
|
||||
return this.grpcService.admin.addSMSProviderTwilio(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* lockout */
|
||||
|
||||
public getLockoutPolicy(): Promise<GetLockoutPolicyResponse.AsObject> {
|
||||
@ -504,6 +555,30 @@ export class AdminService {
|
||||
return this.grpcService.admin.updateLoginPolicy(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* OIDC Configuration */
|
||||
|
||||
public getOIDCSettings(): Promise<GetOIDCSettingsResponse.AsObject> {
|
||||
const req = new GetOIDCSettingsRequest();
|
||||
return this.grpcService.admin.getOIDCSettings(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateOIDCSettings(req: UpdateOIDCSettingsRequest): Promise<UpdateOIDCSettingsResponse.AsObject> {
|
||||
return this.grpcService.admin.updateOIDCSettings(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* LOG and FILE Notifications */
|
||||
|
||||
public getLogNotificationProvider(): Promise<GetLogNotificationProviderResponse.AsObject> {
|
||||
const req = new GetLogNotificationProviderRequest();
|
||||
return this.grpcService.admin.getLogNotificationProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getFileSystemNotificationProvider(
|
||||
req: GetFileSystemNotificationProviderRequest,
|
||||
): Promise<GetFileSystemNotificationProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.getFileSystemNotificationProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* org iam */
|
||||
|
||||
public getCustomOrgIAMPolicy(orgId: string): Promise<GetCustomOrgIAMPolicyResponse.AsObject> {
|
||||
|
@ -816,12 +816,12 @@
|
||||
"LOCKOUT": "Sperrmechanismen",
|
||||
"COMPLEXITY": "Passwordkomplexität",
|
||||
"NOTIFICATIONS": "Benachrichtigungen",
|
||||
"NOTIFICATIONPROVIDERS": "Anbieter und SMTP",
|
||||
"MESSAGETEXTS": "Benachrichtigungstexte",
|
||||
"IDP": "Identity Provider",
|
||||
"LOGINTEXTS": "Login Interface Texte",
|
||||
"BRANDING": "Branding",
|
||||
"PRIVACYPOLICY": "Datenschutzrichtlinie"
|
||||
"PRIVACYPOLICY": "Datenschutzrichtlinie",
|
||||
"OIDC": "OIDC Konfiguration"
|
||||
},
|
||||
"GROUPS": {
|
||||
"NOTIFICATIONS": "Benachrichtigungen",
|
||||
@ -837,6 +837,38 @@
|
||||
"de": "Deutsch",
|
||||
"it": "Italiano",
|
||||
"en": "English"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Einstellungen",
|
||||
"SENDERADDRESS": "Sender Email-Adresse",
|
||||
"SENDERNAME": "Sender Name",
|
||||
"HOST": "Host",
|
||||
"USER": "Benutzer",
|
||||
"PASSWORD": "Passwort",
|
||||
"TLS": "Transport Layer Security (TLS)",
|
||||
"SAVED": "Erfolgreich gespeichert."
|
||||
},
|
||||
"SMS": {
|
||||
"TITLE": "SMS Einstellungen",
|
||||
"PROVIDERS": "Anbieter",
|
||||
"PROVIDER": "SMS Anbieter",
|
||||
"ADDPROVIDER": "Anbieter hinzufügen",
|
||||
"ADDPROVIDERDESCRIPTION": "Wählen Sie einen der verfügbaren Anbieter und geben Sie die erforderlichen Daten ein.",
|
||||
"TWILIO": {
|
||||
"SID": "Sid",
|
||||
"TOKEN": "Token",
|
||||
"SENDERNUMBER": "Sender Number",
|
||||
"ADDED": "Twilio erfolgreich hinzugefügt."
|
||||
}
|
||||
},
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Einstellungen",
|
||||
"ACCESSTOKENLIFETIME": "Access Token Lifetime",
|
||||
"IDTOKENLIFETIME": "Id Token Lifetime",
|
||||
"REFRESHTOKENEXPIRATION": "Refresh Token Expiration",
|
||||
"REFRESHTOKENIDLEEXPIRATION": "Refresh Token Idle Expiration",
|
||||
"INHOURS": "Stunden",
|
||||
"INDAYS": "Tage"
|
||||
}
|
||||
},
|
||||
"POLICY": {
|
||||
|
@ -815,13 +815,13 @@
|
||||
"LOGIN": "Login Behaviour and Security",
|
||||
"LOCKOUT": "Lockout",
|
||||
"COMPLEXITY": "Password complexity",
|
||||
"NOTIFICATIONS": "Notifications",
|
||||
"NOTIFICATIONPROVIDERS": "Notification providers and SMTP",
|
||||
"NOTIFICATIONS": "Notification providers and SMTP",
|
||||
"MESSAGETEXTS": "Message Texts",
|
||||
"IDP": "Identity Providers",
|
||||
"LOGINTEXTS": "Login Interface Texts",
|
||||
"BRANDING": "Branding",
|
||||
"PRIVACYPOLICY": "Privacy Policy"
|
||||
"PRIVACYPOLICY": "Privacy Policy",
|
||||
"OIDC": "OIDC Configuration"
|
||||
},
|
||||
"GROUPS": {
|
||||
"NOTIFICATIONS": "Notifications",
|
||||
@ -837,6 +837,38 @@
|
||||
"de": "Deutsch",
|
||||
"it": "Italiano",
|
||||
"en": "English"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Settings",
|
||||
"SENDERADDRESS": "Sender Email address",
|
||||
"SENDERNAME": "Sender Name",
|
||||
"HOST": "Host",
|
||||
"USER": "User",
|
||||
"PASSWORD": "Password",
|
||||
"TLS": "Transport Layer Security (TLS)",
|
||||
"SAVED": "Saved successfully!"
|
||||
},
|
||||
"SMS": {
|
||||
"TITLE": "SMS Settings",
|
||||
"PROVIDERS": "Providers",
|
||||
"PROVIDER": "SMS Provider",
|
||||
"ADDPROVIDER": "Add SMS Provider",
|
||||
"ADDPROVIDERDESCRIPTION": "Choose one of the available providers and enter the required data.",
|
||||
"TWILIO": {
|
||||
"SID": "Sid",
|
||||
"TOKEN": "Token",
|
||||
"SENDERNUMBER": "Sender Number",
|
||||
"ADDED": "Twilio added successfully."
|
||||
}
|
||||
},
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Settings",
|
||||
"ACCESSTOKENLIFETIME": "Access Token Lifetime",
|
||||
"IDTOKENLIFETIME": "Id Token Lifetime",
|
||||
"REFRESHTOKENEXPIRATION": "Refresh Token Expiration",
|
||||
"REFRESHTOKENIDLEEXPIRATION": "Refresh Token Idle Expiration",
|
||||
"INHOURS": "hours",
|
||||
"INDAYS": "Days"
|
||||
}
|
||||
},
|
||||
"POLICY": {
|
||||
|
@ -806,18 +806,22 @@
|
||||
"TITLE": "Impostazioni dell'istanza",
|
||||
"DESCRIPTION": "Queste impostazioni si applicheranno a tutte le tue organizzazioni a meno che l'impostazione non venga sovrascritta."
|
||||
},
|
||||
"ORG": {
|
||||
"TITLE": "Impostazioni dell'organizzazione",
|
||||
"DESCRIPTION": "Queste impostazioni si applicheranno alla organizzazione corrente."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Generale",
|
||||
"LOGIN": "Comportamento login e sicurezza",
|
||||
"LOCKOUT": "Meccanismi di bloccaggio",
|
||||
"COMPLEXITY": "complessità della password",
|
||||
"NOTIFICATIONS": "Notifiche",
|
||||
"NOTIFICATIONPROVIDERS": "Fornitori e SMTP",
|
||||
"MESSAGETEXTS": "Testi di notifica",
|
||||
"IDP": "Identity Providers",
|
||||
"LOGINTEXTS": "Testi dell'interfaccia login",
|
||||
"BRANDING": "Branding",
|
||||
"PRIVACYPOLICY": "Informativa sulla privacy e TOS"
|
||||
"PRIVACYPOLICY": "Informativa sulla privacy e TOS",
|
||||
"OIDC": "OIDC Configuration"
|
||||
},
|
||||
"GROUPS": {
|
||||
"NOTIFICATIONS": "Notifiche",
|
||||
@ -833,6 +837,38 @@
|
||||
"de": "Deutsch",
|
||||
"it": "Italiano",
|
||||
"en": "English"
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Impostazioni SMTP",
|
||||
"SENDERADDRESS": "Indirizzo email del mittente",
|
||||
"SENDERNAME": "Nome del mittente",
|
||||
"HOST": "Host",
|
||||
"USER": "Utente",
|
||||
"PASSWORD": "Password",
|
||||
"TLS": "Transport Layer Security (TLS)",
|
||||
"SAVED": "Salvato con successo!"
|
||||
},
|
||||
"SMS": {
|
||||
"TITLE": "Impostazioni SMS",
|
||||
"PROVIDERS": "Fornitori",
|
||||
"PROVIDER": "Fornitore SMS",
|
||||
"ADDPROVIDER": "Aggiungi fornitore SMS",
|
||||
"ADDPROVIDERDESCRIPTION": "Scegli uno dei provider disponibili e inserisci i dati richiesti.",
|
||||
"TWILIO": {
|
||||
"SID": "Sid",
|
||||
"TOKEN": "Token",
|
||||
"SENDERNUMBER": "Sender Number",
|
||||
"ADDED": "Twilio aggiunto con successo."
|
||||
}
|
||||
},
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Einstellungen",
|
||||
"ACCESSTOKENLIFETIME": "Access Token Lifetime",
|
||||
"IDTOKENLIFETIME": "Id Token Lifetime",
|
||||
"REFRESHTOKENEXPIRATION": "Refresh Token Expiration",
|
||||
"REFRESHTOKENIDLEEXPIRATION": "Refresh Token Idle Expiration",
|
||||
"INHOURS": "ore",
|
||||
"INDAYS": "giorni"
|
||||
}
|
||||
},
|
||||
"POLICY": {
|
||||
|
@ -1,62 +1,195 @@
|
||||
const avatars = document.getElementsByClassName('lgn-avatar');
|
||||
for (let i = 0; i < avatars.length; i++) {
|
||||
const displayName = avatars[i].getAttribute('loginname');
|
||||
if (displayName) {
|
||||
const username = displayName.split('@')[0];
|
||||
let separator = '_';
|
||||
if (username.includes('-')) {
|
||||
separator = '-';
|
||||
}
|
||||
if (username.includes('.')) {
|
||||
separator = '.';
|
||||
}
|
||||
const split = username.split(separator);
|
||||
const initials = split[0].charAt(0) + (split[1] ? split[1].charAt(0) : '');
|
||||
avatars[i].getElementsByClassName('initials')[0].innerHTML = initials;
|
||||
|
||||
avatars[i].style.background = this.getColor(displayName);
|
||||
// set default white text instead of contrast text mode
|
||||
avatars[i].style.color = '#ffffff';
|
||||
}
|
||||
}
|
||||
|
||||
function getColor(userName) {
|
||||
const colors = [
|
||||
'linear-gradient(40deg, #B44D51 30%, rgb(241,138,138))',
|
||||
'linear-gradient(40deg, #B75073 30%, rgb(234,96,143))',
|
||||
'linear-gradient(40deg, #84498E 30%, rgb(214,116,230))',
|
||||
'linear-gradient(40deg, #705998 30%, rgb(163,131,220))',
|
||||
'linear-gradient(40deg, #5C6598 30%, rgb(135,148,222))',
|
||||
'linear-gradient(40deg, #7F90D3 30%, rgb(181,196,247))',
|
||||
'linear-gradient(40deg, #3E93B9 30%, rgb(150,215,245))',
|
||||
'linear-gradient(40deg, #3494A0 30%, rgb(71,205,222))',
|
||||
'linear-gradient(40deg, #25716A 30%, rgb(58,185,173))',
|
||||
'linear-gradient(40deg, #427E41 30%, rgb(97,185,96))',
|
||||
'linear-gradient(40deg, #89A568 30%, rgb(176,212,133))',
|
||||
'linear-gradient(40deg, #90924D 30%, rgb(187,189,98))',
|
||||
'linear-gradient(40deg, #E2B032 30%, rgb(245,203,99))',
|
||||
'linear-gradient(40deg, #C97358 30%, rgb(245,148,118))',
|
||||
'linear-gradient(40deg, #6D5B54 30%, rgb(152,121,108))',
|
||||
'linear-gradient(40deg, #6B7980 30%, rgb(134,163,177))',
|
||||
];
|
||||
|
||||
let hash = 0;
|
||||
if (userName.length === 0) {
|
||||
return colors[hash];
|
||||
}
|
||||
|
||||
hash = this.hashCode(userName);
|
||||
return colors[hash % colors.length];
|
||||
}
|
||||
const COLORS = [
|
||||
{
|
||||
500: "#ef4444",
|
||||
200: "#fecaca",
|
||||
300: "#fca5a5",
|
||||
600: "#dc2626",
|
||||
700: "#b91c1c",
|
||||
900: "#7f1d1d",
|
||||
},
|
||||
{
|
||||
500: "#f97316",
|
||||
200: "#fed7aa",
|
||||
300: "#fdba74",
|
||||
600: "#ea580c",
|
||||
700: "#c2410c",
|
||||
900: "#7c2d12",
|
||||
},
|
||||
{
|
||||
500: "#f59e0b",
|
||||
200: "#fde68a",
|
||||
300: "#fcd34d",
|
||||
600: "#d97706",
|
||||
700: "#b45309",
|
||||
900: "#78350f",
|
||||
},
|
||||
{
|
||||
500: "#eab308",
|
||||
200: "#fef08a",
|
||||
300: "#fde047",
|
||||
600: "#ca8a04",
|
||||
700: "#a16207",
|
||||
900: "#713f12",
|
||||
},
|
||||
{
|
||||
500: "#84cc16",
|
||||
200: "#d9f99d",
|
||||
300: "#bef264",
|
||||
600: "#65a30d",
|
||||
700: "#4d7c0f",
|
||||
900: "#365314",
|
||||
},
|
||||
{
|
||||
500: "#22c55e",
|
||||
200: "#bbf7d0",
|
||||
300: "#86efac",
|
||||
600: "#16a34a",
|
||||
700: "#15803d",
|
||||
900: "#14532d",
|
||||
},
|
||||
{
|
||||
500: "#10b981",
|
||||
200: "#a7f3d0",
|
||||
300: "#6ee7b7",
|
||||
600: "#059669",
|
||||
700: "#047857",
|
||||
900: "#064e3b",
|
||||
},
|
||||
{
|
||||
500: "#14b8a6",
|
||||
200: "#99f6e4",
|
||||
300: "#5eead4",
|
||||
600: "#0d9488",
|
||||
700: "#0f766e",
|
||||
900: "#134e4a",
|
||||
},
|
||||
{
|
||||
500: "#06b6d4",
|
||||
200: "#a5f3fc",
|
||||
300: "#67e8f9",
|
||||
600: "#0891b2",
|
||||
700: "#0e7490",
|
||||
900: "#164e63",
|
||||
},
|
||||
{
|
||||
500: "#0ea5e9",
|
||||
200: "#bae6fd",
|
||||
300: "#7dd3fc",
|
||||
600: "#0284c7",
|
||||
700: "#0369a1",
|
||||
900: "#0c4a6e",
|
||||
},
|
||||
{
|
||||
500: "#3b82f6",
|
||||
200: "#bfdbfe",
|
||||
300: "#93c5fd",
|
||||
600: "#2563eb",
|
||||
700: "#1d4ed8",
|
||||
900: "#1e3a8a",
|
||||
},
|
||||
{
|
||||
500: "#6366f1",
|
||||
200: "#c7d2fe",
|
||||
300: "#a5b4fc",
|
||||
600: "#4f46e5",
|
||||
700: "#4338ca",
|
||||
900: "#312e81",
|
||||
},
|
||||
{
|
||||
500: "#8b5cf6",
|
||||
200: "#ddd6fe",
|
||||
300: "#c4b5fd",
|
||||
600: "#7c3aed",
|
||||
700: "#6d28d9",
|
||||
900: "#4c1d95",
|
||||
},
|
||||
{
|
||||
500: "#a855f7",
|
||||
200: "#e9d5ff",
|
||||
300: "#d8b4fe",
|
||||
600: "#9333ea",
|
||||
700: "#7e22ce",
|
||||
900: "#581c87",
|
||||
},
|
||||
{
|
||||
500: "#d946ef",
|
||||
200: "#f5d0fe",
|
||||
300: "#f0abfc",
|
||||
600: "#c026d3",
|
||||
700: "#a21caf",
|
||||
900: "#701a75",
|
||||
},
|
||||
{
|
||||
500: "#ec4899",
|
||||
200: "#fbcfe8",
|
||||
300: "#f9a8d4",
|
||||
600: "#db2777",
|
||||
700: "#be185d",
|
||||
900: "#831843",
|
||||
},
|
||||
{
|
||||
500: "#f43f5e",
|
||||
200: "#fecdd3",
|
||||
300: "#fda4af",
|
||||
600: "#e11d48",
|
||||
700: "#be123c",
|
||||
900: "#881337",
|
||||
},
|
||||
];
|
||||
|
||||
function hashCode(str, seed = 0) {
|
||||
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
||||
let h1 = 0xdeadbeef ^ seed,
|
||||
h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
h1 =
|
||||
Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
|
||||
Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 =
|
||||
Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
|
||||
Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
}
|
||||
}
|
||||
|
||||
function getColor(value) {
|
||||
let hash = 0;
|
||||
|
||||
if (value.length === 0) {
|
||||
return COLORS[hash];
|
||||
}
|
||||
|
||||
hash = hashCode(value);
|
||||
return COLORS[hash % COLORS.length];
|
||||
}
|
||||
|
||||
const avatars = document.getElementsByClassName("lgn-avatar");
|
||||
for (let i = 0; i < avatars.length; i++) {
|
||||
const displayName = avatars[i].getAttribute("loginname");
|
||||
if (displayName) {
|
||||
const username = displayName.split("@")[0];
|
||||
let separator = "_";
|
||||
if (username.includes("-")) {
|
||||
separator = "-";
|
||||
}
|
||||
if (username.includes(".")) {
|
||||
separator = ".";
|
||||
}
|
||||
const split = username.split(separator);
|
||||
const initials = split[0].charAt(0) + (split[1] ? split[1].charAt(0) : "");
|
||||
avatars[i].getElementsByClassName("initials")[0].innerHTML = initials;
|
||||
|
||||
const colorPalette = this.getColor(displayName);
|
||||
|
||||
const isDark =
|
||||
document.documentElement.classList.includes("lgn-dark-theme");
|
||||
|
||||
const backgroundShade = isDark ? 900 : 300;
|
||||
const foregroundShade = isDark ? 200 : 900;
|
||||
|
||||
avatars[i].style.background = colorPalette[backgroundShade];
|
||||
avatars[i].style.color = colorPalette[foregroundShade];
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,53 @@
|
||||
@import 'avatar';
|
||||
@import "avatar";
|
||||
@import "../elevation/elevation";
|
||||
|
||||
@mixin lgn-avatar-theme() {
|
||||
@include lgn-avatar-color();
|
||||
@include lgn-avatar-color();
|
||||
}
|
||||
|
||||
@mixin lgn-avatar-color() {
|
||||
.lgn-avatar:not(.transparent) {
|
||||
@include _lgn-avatar-theme-property("background-color", false);
|
||||
@include lgn-avatar-elevation(2);
|
||||
}
|
||||
.lgn-avatar:not(.transparent) {
|
||||
@include _lgn-avatar-theme-property("background-color", false);
|
||||
// @include lgn-avatar-elevation(2);
|
||||
}
|
||||
|
||||
.lgn-avatar .initials{
|
||||
@include _lgn-avatar-theme-property("color", true);
|
||||
}
|
||||
// .lgn-avatar .initials {
|
||||
// @include _lgn-avatar-theme-property("color", true);
|
||||
// }
|
||||
}
|
||||
|
||||
@mixin _lgn-avatar-theme-property($property, $contrast) {
|
||||
$color: if($contrast, var(--zitadel-color-primary-contrast), var(--zitadel-color-primary));
|
||||
$color: if(
|
||||
$contrast,
|
||||
var(--zitadel-color-primary-contrast),
|
||||
var(--zitadel-color-primary)
|
||||
);
|
||||
|
||||
&.lgn-primary {
|
||||
#{$property}: $color;
|
||||
}
|
||||
&.lgn-accent {
|
||||
#{$property}: $color;
|
||||
}
|
||||
&.lgn-warn {
|
||||
#{$property}: $color;
|
||||
}
|
||||
|
||||
&.lgn-primary,
|
||||
&.lgn-accent,
|
||||
&.lgn-warn,
|
||||
&.lgn-primary {
|
||||
#{$property}: $color;
|
||||
}
|
||||
&.lgn-accent {
|
||||
#{$property}: $color;
|
||||
}
|
||||
&.lgn-warn {
|
||||
#{$property}: $color;
|
||||
}
|
||||
|
||||
&.lgn-primary,
|
||||
&.lgn-accent,
|
||||
&.lgn-warn,
|
||||
&[disabled] {
|
||||
&[disabled] {
|
||||
&[disabled] {
|
||||
$btn-color: if($property == "color", var(--zitadel-color-button-disabled), var(--itadel-color-button-disabled-background));
|
||||
#{$property}: $btn-color;
|
||||
}
|
||||
$btn-color: if(
|
||||
$property == "color",
|
||||
var(--zitadel-color-button-disabled),
|
||||
var(--itadel-color-button-disabled-background)
|
||||
);
|
||||
#{$property}: $btn-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin lgn-avatar-elevation($zValue, $opacity: $lgn-elevation-opacity) {
|
||||
@include lgn-elevation($zValue, rgb(0, 0, 0), $opacity);
|
||||
}
|
||||
@include lgn-elevation($zValue, rgb(0, 0, 0), $opacity);
|
||||
}
|
||||
|
@ -2798,9 +2798,6 @@ a:hover, a:active {
|
||||
color: var(--zitadel-color-warn);
|
||||
}
|
||||
|
||||
.lgn-avatar:not(.transparent) {
|
||||
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.lgn-avatar:not(.transparent).lgn-primary {
|
||||
background-color: var(--zitadel-color-primary);
|
||||
}
|
||||
@ -2814,19 +2811,6 @@ a:hover, a:active {
|
||||
background-color: var(--itadel-color-button-disabled-background);
|
||||
}
|
||||
|
||||
.lgn-avatar .initials.lgn-primary {
|
||||
color: var(--zitadel-color-primary-contrast);
|
||||
}
|
||||
.lgn-avatar .initials.lgn-accent {
|
||||
color: var(--zitadel-color-primary-contrast);
|
||||
}
|
||||
.lgn-avatar .initials.lgn-warn {
|
||||
color: var(--zitadel-color-primary-contrast);
|
||||
}
|
||||
.lgn-avatar .initials.lgn-primary[disabled], .lgn-avatar .initials.lgn-accent[disabled], .lgn-avatar .initials.lgn-warn[disabled], .lgn-avatar .initials[disabled][disabled] {
|
||||
color: var(--zitadel-color-button-disabled);
|
||||
}
|
||||
|
||||
.lgn-select, select {
|
||||
background-image: var(--zitadel-icon-select);
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user