feat(console): set email verified on change, user create (#2847)

* feat: set email verified on change

* user create
This commit is contained in:
Max Peintner 2021-12-15 11:23:53 +01:00 committed by GitHub
parent a533872c66
commit fb43b13232
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 289 additions and 251 deletions

View File

@ -1,34 +1,34 @@
<cnsl-detail-layout [backRouterLink]="[ '/users/list/machines']" title="{{ 'USER.CREATE.TITLE' | translate }}"
description="{{ 'USER.CREATE.DESCRIPTION' | translate }}">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
description="{{ 'USER.CREATE.DESCRIPTION' | translate }}">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
<div class="content">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.MACHINE.USERNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="userName" required />
<span cnsl-error *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
<span cnsl-error *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.MACHINE.NAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="name" required />
<span cnsl-error *ngIf="name?.invalid && name?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.MACHINE.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput formControlName="description" />
</cnsl-form-field>
</div>
<div class="btn-container">
<button color="primary" [disabled]="userForm.invalid" type="submit" mat-raised-button>{{ 'ACTIONS.CREATE' |
translate }}</button>
</div>
</form>
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
<div class="content">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.MACHINE.USERNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="userName" required />
<span cnslError *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
<span cnslError *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.MACHINE.NAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="name" required />
<span cnslError *ngIf="name?.invalid && name?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.MACHINE.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput formControlName="description" />
</cnsl-form-field>
</div>
<div class="btn-container">
<button color="primary" [disabled]="userForm.invalid" type="submit" mat-raised-button>{{ 'ACTIONS.CREATE' |
translate }}</button>
</div>
</form>
</cnsl-detail-layout>

View File

@ -1,95 +1,104 @@
<cnsl-detail-layout [backRouterLink]="[ '/users/list/humans']" title="{{ 'USER.CREATE.TITLE' | translate }}"
description="{{ 'USER.CREATE.DESCRIPTION' | translate }}">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
description="{{ 'USER.CREATE.DESCRIPTION' | translate }}">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
<div class="content">
<p class="section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}*</cnsl-label>
<input cnslInput matRipple formControlName="email" required />
<span cnslError *ngIf="email?.invalid && !email?.errors?.required">
{{ 'USER.VALIDATION.NOTANEMAIL' | translate }}
</span>
<span cnslError *ngIf="email?.invalid && email?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="userName" required
[ngStyle]="{'padding-right': suffixPadding ? suffixPadding : '10px'}" />
<span #suffix *ngIf="envSuffixLabel" cnslSuffix>{{envSuffixLabel}}</span>
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
<div class="content">
<p class="section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}*</cnsl-label>
<input cnslInput matRipple formControlName="email" required />
<span cnslError *ngIf="email?.invalid && !email?.errors?.required">
{{ 'USER.VALIDATION.NOTANEMAIL' | translate }}
</span>
<span cnslError *ngIf="email?.invalid && email?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="userName" required
[ngStyle]="{'padding-right': suffixPadding ? suffixPadding : '10px'}" />
<span #suffix *ngIf="envSuffixLabel" cnslSuffix>{{envSuffixLabel}}</span>
<span cnslError *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
<span cnslError *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
</span>
</cnsl-form-field>
</div>
<div class="content">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="firstName" required />
<span cnslError *ngIf="firstName?.invalid && firstName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="lastName" required />
<span cnslError *ngIf="lastName?.invalid && lastName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</cnsl-label>
<input cnslInput formControlName="nickName" />
<span cnslError *ngIf="nickName?.invalid && nickName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<span cnslError *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
<span cnslError *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
</span>
</cnsl-form-field>
</div>
<div class="content">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="firstName" required />
<span cnslError *ngIf="firstName?.invalid && firstName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}*</cnsl-label>
<input cnslInput formControlName="lastName" required />
<span cnslError *ngIf="lastName?.invalid && lastName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.NICKNAME' | translate }}</cnsl-label>
<input cnslInput formControlName="nickName" />
<span cnslError *ngIf="nickName?.invalid && nickName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<p class="section">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
<div class="email-is-verified">
<mat-checkbox class="verified-checkbox" formControlName="isVerified">
{{'USER.LOGINMETHODS.EMAIL.ISVERIFIED' | translate}}
</mat-checkbox>
<cnsl-info-section class="full-width desc">
<span>{{'USER.LOGINMETHODS.EMAIL.ISVERIFIEDDESC' | translate}}</span>
</cnsl-info-section>
</div>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.GENDER' | translate }}</cnsl-label>
<mat-select formControlName="gender">
<mat-option *ngFor="let gender of genders" [value]="gender">
{{ 'GENDERS.'+gender | translate }}
</mat-option>
</mat-select>
<span cnslError *ngIf="gender?.invalid && gender?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
<mat-select formControlName="preferredLanguage">
<mat-option *ngFor="let language of languages" [value]="language">
{{ 'LANGUAGES.'+language | translate }}
</mat-option>
<span cnslError *ngIf="preferredLanguage?.invalid && preferredLanguage?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</mat-select>
</cnsl-form-field>
<p class="section">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
<p class="section">{{ 'USER.CREATE.ADDRESSANDPHONESECTION' | translate }}</p>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.GENDER' | translate }}</cnsl-label>
<mat-select formControlName="gender">
<mat-option *ngFor="let gender of genders" [value]="gender">
{{ 'GENDERS.'+gender | translate }}
</mat-option>
</mat-select>
<span cnslError *ngIf="gender?.invalid && gender?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
<mat-select formControlName="preferredLanguage">
<mat-option *ngFor="let language of languages" [value]="language">
{{ 'LANGUAGES.'+language | translate }}
</mat-option>
<span cnslError *ngIf="preferredLanguage?.invalid && preferredLanguage?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.PHONE' | translate }}</cnsl-label>
<input cnslInput formControlName="phone" />
<span cnslError *ngIf="phone?.invalid && phone?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
</div>
<div class="btn-container">
<button color="primary" [disabled]="userForm.invalid" type="submit" mat-raised-button>{{ 'ACTIONS.CREATE' |
translate }}</button>
</div>
</form>
<p class="section">{{ 'USER.CREATE.ADDRESSANDPHONESECTION' | translate }}</p>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.PHONE' | translate }}</cnsl-label>
<input cnslInput formControlName="phone" />
<span cnslError *ngIf="phone?.invalid && phone?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</span>
</cnsl-form-field>
</div>
<div class="btn-container">
<button color="primary" [disabled]="userForm.invalid" type="submit" mat-raised-button>{{ 'ACTIONS.CREATE' |
translate }}</button>
</div>
</form>
</cnsl-detail-layout>

View File

@ -1,4 +1,3 @@
.form {
width: 100%;
padding-top: 1rem;
@ -7,8 +6,8 @@
button {
margin-top: 3rem;
display: block;
padding: .5rem 4rem;
border-radius: .5rem;
padding: 0.5rem 4rem;
border-radius: 0.5rem;
}
}
}
@ -18,19 +17,25 @@
display: flex;
flex-wrap: wrap;
flex-direction: row;
margin: 0 -.5rem;
margin: 0 -0.5rem;
.section {
padding: .5rem;
padding: 0.5rem;
flex-basis: 100%;
color: var(--grey);
font-size: .9rem;
letter-spacing: .05em;
font-size: 0.9rem;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.formfield {
flex: 1 0 33%;
margin: 0 .5rem;
margin: 0 0.5rem;
}
.email-is-verified {
margin: 0 0.5rem;
flex-basis: 100%;
margin-top: 1.5rem;
}
}

View File

@ -38,26 +38,29 @@ export class UserCreateComponent implements OnDestroy {
) {
this.loading = true;
this.loadOrg();
this.mgmtService.getOrgIAMPolicy().then((resp) => {
if (resp.policy?.userLoginMustBeDomain) {
this.userLoginMustBeDomain = resp.policy.userLoginMustBeDomain;
}
this.initForm();
this.loading = false;
this.envSuffixLabel = this.envSuffix();
this.changeDetRef.detectChanges();
}).catch(error => {
console.error(error);
this.initForm();
this.loading = false;
this.envSuffixLabel = this.envSuffix();
this.changeDetRef.detectChanges();
});
this.mgmtService
.getOrgIAMPolicy()
.then((resp) => {
if (resp.policy?.userLoginMustBeDomain) {
this.userLoginMustBeDomain = resp.policy.userLoginMustBeDomain;
}
this.initForm();
this.loading = false;
this.envSuffixLabel = this.envSuffix();
this.changeDetRef.detectChanges();
})
.catch((error) => {
console.error(error);
this.initForm();
this.loading = false;
this.envSuffixLabel = this.envSuffix();
this.changeDetRef.detectChanges();
});
}
private async loadOrg(): Promise<void> {
const domains = (await this.mgmtService.listOrgDomains());
const found = domains.resultList.find(resp => resp.isPrimary);
const domains = await this.mgmtService.listOrgDomains();
const found = domains.resultList.find((resp) => resp.isPrimary);
if (found) {
this.primaryDomain = found;
}
@ -66,32 +69,26 @@ export class UserCreateComponent implements OnDestroy {
private initForm(): void {
this.userForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
userName: ['',
[
Validators.required,
Validators.minLength(2),
],
],
userName: ['', [Validators.required, Validators.minLength(2)]],
firstName: ['', Validators.required],
lastName: ['', Validators.required],
nickName: [''],
gender: [],
preferredLanguage: [''],
phone: [''],
isVerified: [false, []],
});
this.userForm.controls['phone'].valueChanges.pipe(
takeUntil(this.destroyed$),
debounceTime(300)).subscribe(value => {
const phoneNumber = parsePhoneNumber(value ?? '', 'CH');
if (phoneNumber) {
const formmatted = phoneNumber.formatInternational();
const country = phoneNumber.country;
if (this.phone && country && this.phone.value && this.phone.value !== formmatted) {
this.phone.setValue(formmatted);
}
this.userForm.controls['phone'].valueChanges.pipe(takeUntil(this.destroyed$), debounceTime(300)).subscribe((value) => {
const phoneNumber = parsePhoneNumber(value ?? '', 'CH');
if (phoneNumber) {
const formmatted = phoneNumber.formatInternational();
const country = phoneNumber.country;
if (this.phone && country && this.phone.value && this.phone.value !== formmatted) {
this.phone.setValue(formmatted);
}
});
}
});
}
public createUser(): void {
@ -110,7 +107,10 @@ export class UserCreateComponent implements OnDestroy {
humanReq.setUserName(this.userName?.value);
humanReq.setProfile(profileReq);
humanReq.setEmail(new AddHumanUserRequest.Email().setEmail(this.email?.value));
const emailreq = new AddHumanUserRequest.Email();
emailreq.setEmail(this.email?.value);
emailreq.setIsEmailVerified(this.isVerified?.value);
humanReq.setEmail(emailreq);
if (this.phone && this.phone.value) {
humanReq.setPhone(new AddHumanUserRequest.Phone().setPhone(this.phone.value));
@ -123,7 +123,7 @@ export class UserCreateComponent implements OnDestroy {
this.toast.showInfo('USER.TOAST.CREATED', true);
this.router.navigate(['users', data.userId]);
})
.catch(error => {
.catch((error) => {
this.loading = false;
this.toast.showError(error);
});
@ -137,6 +137,9 @@ export class UserCreateComponent implements OnDestroy {
public get email(): AbstractControl | null {
return this.userForm.get('email');
}
public get isVerified(): AbstractControl | null {
return this.userForm.get('isVerified');
}
public get userName(): AbstractControl | null {
return this.userForm.get('userName');
}

View File

@ -11,29 +11,31 @@ import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
import { InputModule } from 'src/app/modules/input/input.module';
import { UserCreateRoutingModule } from './user-create-routing.module';
import { UserCreateComponent } from './user-create.component';
@NgModule({
declarations: [UserCreateComponent],
imports: [
UserCreateRoutingModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
MatSelectModule,
MatButtonModule,
MatIconModule,
MatProgressSpinnerModule,
MatProgressBarModule,
MatCheckboxModule,
MatTooltipModule,
TranslateModule,
DetailLayoutModule,
InputModule,
MatRippleModule,
],
declarations: [UserCreateComponent],
imports: [
UserCreateRoutingModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
MatSelectModule,
MatButtonModule,
MatIconModule,
MatProgressSpinnerModule,
MatProgressBarModule,
MatCheckboxModule,
MatTooltipModule,
TranslateModule,
InfoSectionModule,
DetailLayoutModule,
InputModule,
MatRippleModule,
],
})
export class UserCreateModule { }
export class UserCreateModule {}

View File

@ -27,11 +27,11 @@
.btn-container {
display: flex;
justify-content: flex-end;
margin: 0 -.5rem;
margin: 0 -0.5rem;
button {
border-radius: .5rem;
margin: 0 .5rem;
border-radius: 0.5rem;
margin: 0 0.5rem;
}
}
@ -39,11 +39,11 @@
display: flex;
flex-wrap: wrap;
align-items: stretch;
margin: -1.5rem -.5rem;
margin: -1.5rem -0.5rem;
.app-card {
flex: 1;
margin: .5rem;
margin: 0.5rem;
}
}
@ -55,6 +55,7 @@
.resendemail {
margin-right: 1rem;
margin-top: 0.5rem;
}
.side-padding {

View File

@ -227,9 +227,9 @@ export class AuthUserDetailComponent implements OnDestroy {
width: '400px',
});
dialogRefPhone.afterClosed().subscribe((resp) => {
if (resp) {
this.savePhone(resp);
dialogRefPhone.afterClosed().subscribe((resp: { value: string; isVerified: boolean }) => {
if (resp && resp.value) {
this.savePhone(resp.value);
}
});
break;
@ -247,9 +247,9 @@ export class AuthUserDetailComponent implements OnDestroy {
width: '400px',
});
dialogRefEmail.afterClosed().subscribe((resp) => {
if (resp) {
this.saveEmail(resp);
dialogRefEmail.afterClosed().subscribe((resp: { value: string; isVerified: boolean }) => {
if (resp && resp.value) {
this.saveEmail(resp.value);
}
});
break;

View File

@ -1,22 +1,32 @@
<h1 mat-dialog-title>
<span class="title">{{data.titleKey | translate}}</span>
<span class="title">{{data.titleKey | translate}}</span>
</h1>
<p class="desc">{{data.descriptionKey | translate}}</p>
<div mat-dialog-content>
<cnsl-form-field class="formfield">
<cnsl-label>{{data.labelKey | translate }} <span *ngIf="isPhone && phoneCountry">({{ phoneCountry }})</span>
</cnsl-label>
<input [formControl]="valueControl" cnslInput
(keydown.enter)="valueControl.valid ? closeDialogWithValue() : null" />
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{data.labelKey | translate }} <span *ngIf="isPhone && phoneCountry">({{ phoneCountry }})</span>
</cnsl-label>
<input [formControl]="valueControl" cnslInput
(keydown.enter)="valueControl.valid ? closeDialogWithValue() : null" />
</cnsl-form-field>
<ng-container *ngIf="data.type === EditDialogType.EMAIL && data.isVerifiedTextKey">
<mat-checkbox class="verified-checkbox" [(ngModel)]="isVerified">
{{data.isVerifiedTextKey |
translate}}
</mat-checkbox>
<cnsl-info-section class="full-width desc">
<span>{{data.isVerifiedTextDescKey | translate}}</span>
</cnsl-info-section>
</ng-container>
</div>
<div mat-dialog-actions class="action">
<button cdkFocusInitial color="primary" mat-button class="ok-button" (click)="closeDialog()">
{{data.cancelKey | translate}}
</button>
<button cdkFocusInitial color="primary" mat-button class="ok-button" (click)="closeDialog()">
{{data.cancelKey | translate}}
</button>
<button [disabled]="valueControl.invalid" cdkFocusInitial color="primary" mat-raised-button class="ok-button"
(click)="closeDialogWithValue()">
{{data.confirmKey | translate}}
</button>
<button [disabled]="valueControl.invalid" cdkFocusInitial color="primary" mat-raised-button class="ok-button"
(click)="closeDialogWithValue()">
{{data.confirmKey | translate}}
</button>
</div>

View File

@ -2,6 +2,10 @@
width: 100%;
}
.verified-checkbox {
margin-top: 1.5rem;
}
.desc {
font-size: 14px;
color: var(--grey);
@ -12,10 +16,10 @@
justify-content: flex-end;
.ok-button {
margin-left: .5rem;
margin-left: 0.5rem;
}
button {
border-radius: .5rem;
border-radius: 0.5rem;
}
}

View File

@ -15,16 +15,17 @@ export enum EditDialogType {
})
export class EditDialogComponent {
public isPhone: boolean = false;
public isVerified: boolean = false;
public phoneCountry: string = 'CH';
public valueControl: FormControl = new FormControl(['', [Validators.required]]);
constructor(public dialogRef: MatDialogRef<EditDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {
public EditDialogType: any = EditDialogType;
constructor(public dialogRef: MatDialogRef<EditDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {
this.valueControl.setValue(data.value);
if (data.type === EditDialogType.PHONE) {
this.isPhone = true;
}
this.valueControl.valueChanges.subscribe(value => {
this.valueControl.valueChanges.subscribe((value) => {
if (value && value.length > 1) {
this.changeValue(value);
}
@ -53,6 +54,6 @@ export class EditDialogComponent {
}
closeDialogWithValue(): void {
this.dialogRef.close(this.valueControl.value);
this.dialogRef.close({ value: this.valueControl.value, isVerified: this.isVerified });
}
}

View File

@ -19,7 +19,7 @@
}
p {
margin: .5rem 0;
margin: 0.5rem 0;
font-size: 14px;
color: var(--grey);
}
@ -30,13 +30,13 @@
}
.actions-trigger {
margin-top: .25rem;
margin-top: 0.25rem;
display: flex;
align-items: center;
.icon {
margin-left: .5rem;
margin-right: -.5rem;
margin-left: 0.5rem;
margin-right: -0.5rem;
}
}
}
@ -66,3 +66,7 @@
.side-padding {
padding-top: 1rem;
}
.resendemail {
margin-top: 0.5rem;
}

View File

@ -229,10 +229,10 @@ export class UserDetailComponent implements OnInit {
});
}
public saveEmail(email: string): void {
public saveEmail(email: string, isVerified: boolean): void {
if (this.user.id && email) {
this.mgmtUserService
.updateHumanEmail(this.user.id, email)
.updateHumanEmail(this.user.id, email, isVerified)
.then(() => {
this.toast.showInfo('USER.TOAST.EMAILSAVED', true);
if (this.user.state === UserState.USER_STATE_INITIAL) {
@ -355,9 +355,9 @@ export class UserDetailComponent implements OnInit {
width: '400px',
});
dialogRefPhone.afterClosed().subscribe((resp) => {
if (resp) {
this.savePhone(resp);
dialogRefPhone.afterClosed().subscribe((resp: { value: string; isVerified: boolean }) => {
if (resp && resp.value) {
this.savePhone(resp.value);
}
});
break;
@ -369,15 +369,17 @@ export class UserDetailComponent implements OnInit {
labelKey: 'ACTIONS.NEWVALUE',
titleKey: 'USER.LOGINMETHODS.EMAIL.EDITTITLE',
descriptionKey: 'USER.LOGINMETHODS.EMAIL.EDITDESC',
isVerifiedTextKey: 'USER.LOGINMETHODS.EMAIL.ISVERIFIED',
isVerifiedTextDescKey: 'USER.LOGINMETHODS.EMAIL.ISVERIFIEDDESC',
value: this.user.human?.email?.email,
type: EditDialogType.EMAIL,
},
width: '400px',
});
dialogRefEmail.afterClosed().subscribe((resp) => {
if (resp) {
this.saveEmail(resp);
dialogRefEmail.afterClosed().subscribe((resp: { value: string; isVerified: boolean }) => {
if (resp && resp.value) {
this.saveEmail(resp.value, resp.isVerified);
}
});
break;

View File

@ -899,32 +899,24 @@ export class ManagementService {
return this.grpcService.mgmt.listHumanLinkedIDPs(req, null).then((resp) => resp.toObject());
}
public getAction(
id: string,
): Promise<GetActionResponse.AsObject> {
public getAction(id: string): Promise<GetActionResponse.AsObject> {
const req = new GetActionRequest();
req.setId(id);
return this.grpcService.mgmt.getAction(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.getAction(req, null).then((resp) => resp.toObject());
}
public createAction(
req: CreateActionRequest,
): Promise<CreateActionResponse.AsObject> {
return this.grpcService.mgmt.createAction(req, null).then(resp => resp.toObject());
public createAction(req: CreateActionRequest): Promise<CreateActionResponse.AsObject> {
return this.grpcService.mgmt.createAction(req, null).then((resp) => resp.toObject());
}
public updateAction(
req: UpdateActionRequest,
): Promise<UpdateActionResponse.AsObject> {
return this.grpcService.mgmt.updateAction(req, null).then(resp => resp.toObject());
public updateAction(req: UpdateActionRequest): Promise<UpdateActionResponse.AsObject> {
return this.grpcService.mgmt.updateAction(req, null).then((resp) => resp.toObject());
}
public deleteAction(
id: string,
): Promise<DeleteActionResponse.AsObject> {
public deleteAction(id: string): Promise<DeleteActionResponse.AsObject> {
const req = new DeleteActionRequest();
req.setId(id);
return this.grpcService.mgmt.deleteAction(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.deleteAction(req, null).then((resp) => resp.toObject());
}
public listActions(
@ -949,23 +941,19 @@ export class ManagementService {
metadata.setAsc(asc);
}
req.setQuery(metadata);
return this.grpcService.mgmt.listActions(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.listActions(req, null).then((resp) => resp.toObject());
}
public getFlow(
type: FlowType
): Promise<GetFlowResponse.AsObject> {
public getFlow(type: FlowType): Promise<GetFlowResponse.AsObject> {
const req = new GetFlowRequest();
req.setType(type);
return this.grpcService.mgmt.getFlow(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.getFlow(req, null).then((resp) => resp.toObject());
}
public clearFlow(
type: FlowType
): Promise<ClearFlowResponse.AsObject> {
public clearFlow(type: FlowType): Promise<ClearFlowResponse.AsObject> {
const req = new ClearFlowRequest();
req.setType(type);
return this.grpcService.mgmt.clearFlow(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.clearFlow(req, null).then((resp) => resp.toObject());
}
public setTriggerActions(
@ -977,7 +965,7 @@ export class ManagementService {
req.setActionIdsList(actionIdsList);
req.setFlowType(type);
req.setTriggerType(triggerType);
return this.grpcService.mgmt.setTriggerActions(req, null).then(resp => resp.toObject());
return this.grpcService.mgmt.setTriggerActions(req, null).then((resp) => resp.toObject());
}
public getIAM(): Promise<GetIAMResponse.AsObject> {
@ -1468,10 +1456,13 @@ export class ManagementService {
return this.grpcService.mgmt.getHumanEmail(req, null).then((resp) => resp.toObject());
}
public updateHumanEmail(userId: string, email: string): Promise<UpdateHumanEmailResponse.AsObject> {
public updateHumanEmail(userId: string, email: string, isVerified?: boolean): Promise<UpdateHumanEmailResponse.AsObject> {
const req = new UpdateHumanEmailRequest();
req.setUserId(userId);
req.setEmail(email);
if (isVerified) {
req.setIsEmailVerified(isVerified);
}
return this.grpcService.mgmt.updateHumanEmail(req, null).then((resp) => resp.toObject());
}

View File

@ -419,6 +419,8 @@
"EMAIL": {
"TITLE": "E-Mail",
"VALID": "Validiert",
"ISVERIFIED": "Email Verifiziert",
"ISVERIFIEDDESC": "Wenn die Email als verifiziert angegeben wird, wird keine Initialisierungsmail versendet.",
"RESEND": "Verifikationsmail erneut senden",
"EDITTITLE": "Email ändern",
"EDITDESC": "Geben Sie die neue Email in dem darunterliegenden Feld ein!"

View File

@ -419,6 +419,8 @@
"EMAIL": {
"TITLE": "E-mail",
"VALID": "validated",
"ISVERIFIED": "Email Verified",
"ISVERIFIEDDESC": "If the email is indicated as verified, no initialization email will be sent.",
"RESEND": "Resend Verification E-mail",
"EDITTITLE": "Change Email",
"EDITDESC": "Enter the new email in the field below."

View File

@ -419,6 +419,8 @@
"EMAIL": {
"TITLE": "E-mail",
"VALID": "convalidato",
"ISVERIFIED": "Email Verificato",
"ISVERIFIEDDESC": "Se l'email viene indicata come verificata, non verrà inviata alcuna email di inizializzazione.",
"RESEND": "Invia di nuovo l'e-mail di verifica",
"EDITTITLE": "Cambiare l'e-mail",
"EDITDESC": "Inserisci la nuova email nel campo sottostante."