mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-13 01:22:14 +00:00
fix(console): better error messages (#5409)
* fix(console): better error messages * fix: fix i18n error labels * rollout cnsl-i18n-errors * move errors to form-field * fix: form control errors * rollout validators * translate * replace variables * lint * self review * fix confirm validation * use help observable * fix validation errors * cleanup * custom validator for idp templates * lint * validate on blur * remove element --------- Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import {
|
||||
MatLegacyDialogRef as MatDialogRef,
|
||||
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
|
||||
} from '@angular/material/legacy-dialog';
|
||||
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { Action, FlowType, TriggerType } from 'src/app/proto/generated/zitadel/action_pb';
|
||||
import { SetTriggerActionsRequest } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
@@ -34,8 +35,8 @@ export class AddFlowDialogComponent {
|
||||
}
|
||||
|
||||
this.form = this.fb.group({
|
||||
triggerType: [data.triggerType ? data.triggerType : '', [Validators.required]],
|
||||
actionIdsList: [data.actions ? (data.actions as Action.AsObject[]).map((a) => a.id) : [], [Validators.required]],
|
||||
triggerType: [data.triggerType ? data.triggerType : '', [requiredValidator]],
|
||||
actionIdsList: [data.actions ? (data.actions as Action.AsObject[]).map((a) => a.id) : [], [requiredValidator]],
|
||||
});
|
||||
|
||||
this.getActionIds();
|
||||
|
||||
@@ -57,37 +57,22 @@
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userName" required />
|
||||
<span cnslError *ngIf="userName?.invalid && userName?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="email" required />
|
||||
<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.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 cnsl-secondary-text">{{ 'USER.CREATE.GENDERLANGSECTION' | translate }}</p>
|
||||
@@ -99,9 +84,6 @@
|
||||
{{ '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>
|
||||
@@ -109,9 +91,6 @@
|
||||
<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>
|
||||
|
||||
@@ -148,10 +127,6 @@
|
||||
<cnsl-form-field class="pwd" *ngIf="password">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEW' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="firstpassword" formControlName="password" type="password" />
|
||||
|
||||
<span cnslError *ngIf="password?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="pwd" *ngIf="confirmPassword">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</cnsl-label>
|
||||
@@ -162,13 +137,6 @@
|
||||
formControlName="confirmPassword"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
</ng-container>
|
||||
|
||||
@@ -4,7 +4,15 @@ import { Component } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { MatLegacySlideToggleChange as MatSlideToggleChange } from '@angular/material/legacy-slide-toggle';
|
||||
import { Router } from '@angular/router';
|
||||
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators';
|
||||
import {
|
||||
containsLowerCaseValidator,
|
||||
containsNumberValidator,
|
||||
containsSymbolValidator,
|
||||
containsUpperCaseValidator,
|
||||
minLengthValidator,
|
||||
passwordConfirmValidator,
|
||||
requiredValidator,
|
||||
} from 'src/app/modules/form-field/validators/validators';
|
||||
import { SetUpOrgRequest } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { Gender } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
@@ -13,26 +21,6 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
function passwordConfirmValidator(c: AbstractControl): any {
|
||||
if (!c.parent || !c) {
|
||||
return;
|
||||
}
|
||||
const pwd = c.parent.get('password');
|
||||
const cpwd = c.parent.get('confirmPassword');
|
||||
|
||||
if (!pwd || !cpwd) {
|
||||
return;
|
||||
}
|
||||
if (pwd.value !== cpwd.value) {
|
||||
return {
|
||||
invalid: true,
|
||||
notequal: {
|
||||
valid: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-org-create',
|
||||
templateUrl: './org-create.component.html',
|
||||
@@ -49,7 +37,7 @@ function passwordConfirmValidator(c: AbstractControl): any {
|
||||
})
|
||||
export class OrgCreateComponent {
|
||||
public orgForm: UntypedFormGroup = this.fb.group({
|
||||
name: ['', [Validators.required]],
|
||||
name: ['', [requiredValidator]],
|
||||
domain: [''],
|
||||
});
|
||||
|
||||
@@ -133,10 +121,10 @@ export class OrgCreateComponent {
|
||||
|
||||
private initForm(): void {
|
||||
this.userForm = this.fb.group({
|
||||
userName: ['', [Validators.required]],
|
||||
firstName: ['', [Validators.required]],
|
||||
lastName: ['', [Validators.required]],
|
||||
email: ['', [Validators.required]],
|
||||
userName: ['', [requiredValidator]],
|
||||
firstName: ['', [requiredValidator]],
|
||||
lastName: ['', [requiredValidator]],
|
||||
email: ['', [requiredValidator]],
|
||||
isVerified: [false, []],
|
||||
gender: [''],
|
||||
nickName: [''],
|
||||
@@ -145,7 +133,7 @@ export class OrgCreateComponent {
|
||||
}
|
||||
|
||||
public initPwdValidators(): void {
|
||||
const validators: Validators[] = [Validators.required];
|
||||
const validators: Validators[] = [requiredValidator];
|
||||
|
||||
if (this.usePassword) {
|
||||
this.mgmtService.getDefaultPasswordComplexityPolicy().then((data) => {
|
||||
@@ -153,23 +141,23 @@ export class OrgCreateComponent {
|
||||
this.policy = data.policy;
|
||||
|
||||
if (this.policy.minLength) {
|
||||
validators.push(Validators.minLength(this.policy.minLength));
|
||||
validators.push(minLengthValidator(this.policy.minLength));
|
||||
}
|
||||
if (this.policy.hasLowercase) {
|
||||
validators.push(lowerCaseValidator);
|
||||
validators.push(containsLowerCaseValidator);
|
||||
}
|
||||
if (this.policy.hasUppercase) {
|
||||
validators.push(upperCaseValidator);
|
||||
validators.push(containsUpperCaseValidator);
|
||||
}
|
||||
if (this.policy.hasNumber) {
|
||||
validators.push(numberValidator);
|
||||
validators.push(containsNumberValidator);
|
||||
}
|
||||
if (this.policy.hasSymbol) {
|
||||
validators.push(symbolValidator);
|
||||
validators.push(containsSymbolValidator);
|
||||
}
|
||||
|
||||
const pwdValidators = [...validators] as ValidatorFn[];
|
||||
const confirmPwdValidators = [...validators, passwordConfirmValidator] as ValidatorFn[];
|
||||
const confirmPwdValidators = [requiredValidator, passwordConfirmValidator()] as ValidatorFn[];
|
||||
this.pwdForm = this.fb.group({
|
||||
password: ['', pwdValidators],
|
||||
confirmPassword: ['', confirmPwdValidators],
|
||||
@@ -189,13 +177,13 @@ export class OrgCreateComponent {
|
||||
this.createSteps = 1;
|
||||
|
||||
this.orgForm = this.fb.group({
|
||||
name: ['', [Validators.required]],
|
||||
name: ['', [requiredValidator]],
|
||||
});
|
||||
} else {
|
||||
this.createSteps = 2;
|
||||
|
||||
this.orgForm = this.fb.group({
|
||||
name: ['', [Validators.required]],
|
||||
name: ['', [requiredValidator]],
|
||||
domain: [''],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
<cnsl-form-field class="name-formfield">
|
||||
<cnsl-label>{{ 'APP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput cdkFocusInitial formControlName="name" />
|
||||
<span cnslError *ngIf="name?.errors?.required">{{ 'PROJECT.APP.NAMEREQUIRED' | translate }}</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<p class="step-title">{{ 'APP.TYPETITLE' | translate }}</p>
|
||||
|
||||
@@ -2,13 +2,14 @@ import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { Buffer } from 'buffer';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
|
||||
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import {
|
||||
APIAuthMethodType,
|
||||
OIDCAppType,
|
||||
@@ -127,8 +128,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.form = this.fb.group({
|
||||
name: ['', [Validators.required]],
|
||||
appType: ['', [Validators.required]],
|
||||
name: ['', [requiredValidator]],
|
||||
appType: ['', [requiredValidator]],
|
||||
// apptype OIDC
|
||||
responseTypesList: ['', []],
|
||||
grantTypesList: ['', []],
|
||||
@@ -140,8 +141,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
this.initForm();
|
||||
|
||||
this.firstFormGroup = this.fb.group({
|
||||
name: ['', [Validators.required]],
|
||||
appType: [WEB_TYPE, [Validators.required]],
|
||||
name: ['', [requiredValidator]],
|
||||
appType: [WEB_TYPE, [requiredValidator]],
|
||||
});
|
||||
|
||||
this.samlConfigForm = this.fb.group({
|
||||
@@ -192,7 +193,7 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.secondFormGroup = this.fb.group({
|
||||
authMethod: [this.authMethods[0].key, [Validators.required]],
|
||||
authMethod: [this.authMethods[0].key, [requiredValidator]],
|
||||
});
|
||||
|
||||
this.secondFormGroup.valueChanges.subscribe((form) => {
|
||||
@@ -276,8 +277,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
public setDevFormValidators(): void {
|
||||
if (this.isDevOIDC) {
|
||||
const grantTypesControl = new UntypedFormControl('', [Validators.required]);
|
||||
const responseTypesControl = new UntypedFormControl('', [Validators.required]);
|
||||
const grantTypesControl = new UntypedFormControl('', [requiredValidator]);
|
||||
const responseTypesControl = new UntypedFormControl('', [requiredValidator]);
|
||||
|
||||
this.form.addControl('grantTypesList', grantTypesControl);
|
||||
this.form.addControl('responseTypesList', responseTypesControl);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { animate, animateChild, query, stagger, style, transition, trigger } from '@angular/animations';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { BulkAddProjectRolesRequest } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
@@ -32,7 +33,7 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
public formArray!: UntypedFormArray;
|
||||
public formGroup: UntypedFormGroup = this.fb.group({
|
||||
key: new UntypedFormControl('', [Validators.required]),
|
||||
key: new UntypedFormControl('', [requiredValidator]),
|
||||
displayName: new UntypedFormControl(''),
|
||||
group: new UntypedFormControl(''),
|
||||
});
|
||||
@@ -50,7 +51,7 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
public addEntry(): void {
|
||||
const newGroup = this.fb.group({
|
||||
key: new UntypedFormControl('', [Validators.required]),
|
||||
key: new UntypedFormControl('', [requiredValidator]),
|
||||
displayName: new UntypedFormControl(''),
|
||||
group: new UntypedFormControl(''),
|
||||
});
|
||||
|
||||
@@ -12,19 +12,10 @@
|
||||
<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>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { minLengthValidator, requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { AddMachineUserRequest } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AccessTokenType } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
@@ -45,8 +46,8 @@ export class UserCreateMachineComponent implements OnDestroy {
|
||||
|
||||
private initForm(): void {
|
||||
this.userForm = this.fb.group({
|
||||
userName: ['', [Validators.required, Validators.minLength(2)]],
|
||||
name: ['', [Validators.required]],
|
||||
userName: ['', [requiredValidator, minLengthValidator(2)]],
|
||||
name: ['', [requiredValidator]],
|
||||
description: ['', []],
|
||||
accessTokenType: [AccessTokenType.ACCESS_TOKEN_TYPE_BEARER, []],
|
||||
});
|
||||
|
||||
@@ -15,12 +15,6 @@
|
||||
<cnsl-form-field>
|
||||
<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>
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
|
||||
@@ -31,35 +25,19 @@
|
||||
[ngStyle]="{ 'padding-right': suffixPadding ? suffixPadding : '10px' }"
|
||||
/>
|
||||
<span #suffix *ngIf="envSuffix" cnslSuffix>{{ envSuffix }}</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>
|
||||
|
||||
<cnsl-form-field>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@@ -84,10 +62,6 @@
|
||||
<cnsl-form-field *ngIf="password">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEWINITIAL' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="firstpassword" formControlName="password" type="password" />
|
||||
|
||||
<span cnslError *ngIf="password?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field *ngIf="confirmPassword">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRMINITIAL' | translate }}</cnsl-label>
|
||||
@@ -98,13 +72,6 @@
|
||||
formControlName="confirmPassword"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</form>
|
||||
@@ -120,9 +87,6 @@
|
||||
{{ '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>
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
@@ -130,9 +94,6 @@
|
||||
<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>
|
||||
</div>
|
||||
@@ -154,9 +115,6 @@
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.PHONE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phone" matTooltip="{{ 'USER.PROFILE.PHONE_HINT' | translate }}" />
|
||||
<span cnslError *ngIf="phone?.invalid && phone?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,27 +13,17 @@ import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { CountryCallingCodesService, CountryPhoneCode } from 'src/app/services/country-calling-codes.service';
|
||||
import { formatPhone } from 'src/app/utils/formatPhone';
|
||||
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../../validators';
|
||||
|
||||
function passwordConfirmValidator(c: AbstractControl): any {
|
||||
if (!c.parent || !c) {
|
||||
return;
|
||||
}
|
||||
const pwd = c.parent.get('password');
|
||||
const cpwd = c.parent.get('confirmPassword');
|
||||
|
||||
if (!pwd || !cpwd) {
|
||||
return;
|
||||
}
|
||||
if (pwd.value !== cpwd.value) {
|
||||
return {
|
||||
invalid: true,
|
||||
notequal: {
|
||||
valid: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
import {
|
||||
containsLowerCaseValidator,
|
||||
containsNumberValidator,
|
||||
containsSymbolValidator,
|
||||
containsUpperCaseValidator,
|
||||
emailValidator,
|
||||
minLengthValidator,
|
||||
passwordConfirmValidator,
|
||||
phoneValidator,
|
||||
requiredValidator,
|
||||
} from '../../../modules/form-field/validators/validators';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-user-create',
|
||||
@@ -113,40 +103,40 @@ export class UserCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
private initForm(): void {
|
||||
this.userForm = this.fb.group({
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
userName: ['', [Validators.required, Validators.minLength(2)]],
|
||||
firstName: ['', Validators.required],
|
||||
lastName: ['', Validators.required],
|
||||
email: ['', [requiredValidator, emailValidator]],
|
||||
userName: ['', [requiredValidator, minLengthValidator(2)]],
|
||||
firstName: ['', requiredValidator],
|
||||
lastName: ['', requiredValidator],
|
||||
nickName: [''],
|
||||
gender: [],
|
||||
preferredLanguage: [''],
|
||||
phone: [''],
|
||||
phone: ['', phoneValidator],
|
||||
isVerified: [false, []],
|
||||
});
|
||||
|
||||
const validators: Validators[] = [Validators.required];
|
||||
const validators: Validators[] = [requiredValidator];
|
||||
|
||||
this.mgmtService.getPasswordComplexityPolicy().then((data) => {
|
||||
if (data.policy) {
|
||||
this.policy = data.policy;
|
||||
|
||||
if (this.policy.minLength) {
|
||||
validators.push(Validators.minLength(this.policy.minLength));
|
||||
validators.push(minLengthValidator(this.policy.minLength));
|
||||
}
|
||||
if (this.policy.hasLowercase) {
|
||||
validators.push(lowerCaseValidator);
|
||||
validators.push(containsLowerCaseValidator);
|
||||
}
|
||||
if (this.policy.hasUppercase) {
|
||||
validators.push(upperCaseValidator);
|
||||
validators.push(containsUpperCaseValidator);
|
||||
}
|
||||
if (this.policy.hasNumber) {
|
||||
validators.push(numberValidator);
|
||||
validators.push(containsNumberValidator);
|
||||
}
|
||||
if (this.policy.hasSymbol) {
|
||||
validators.push(symbolValidator);
|
||||
validators.push(containsSymbolValidator);
|
||||
}
|
||||
const pwdValidators = [...validators] as ValidatorFn[];
|
||||
const confirmPwdValidators = [...validators, passwordConfirmValidator] as ValidatorFn[];
|
||||
const confirmPwdValidators = [requiredValidator, passwordConfirmValidator()] as ValidatorFn[];
|
||||
|
||||
this.pwdForm = this.fb.group({
|
||||
password: ['', pwdValidators],
|
||||
@@ -203,14 +193,13 @@ export class UserCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
public setCountryCallingCode(): void {
|
||||
let value = (this.phone?.value as string) || '';
|
||||
this.phone?.setValue('+' + this.selected?.countryCallingCode + ' ' + value.replace(/\+[0-9]*\s/, ''));
|
||||
this.countryPhoneCodes.forEach((code) => (value = value.replace(`+${code.countryCallingCode}`, '')));
|
||||
value = value.trim();
|
||||
this.phone?.setValue('+' + this.selected?.countryCallingCode + ' ' + value);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Set default selected country for phone numbers
|
||||
const defaultCountryCallingCode = 'CH';
|
||||
this.countryPhoneCodes = this.countryCallingCodesService.getCountryCallingCodes();
|
||||
this.selected = this.countryPhoneCodes.find((code) => code.countryCode === defaultCountryCallingCode);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { MediaMatcher } from '@angular/cdk/layout';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, EventEmitter, OnDestroy } from '@angular/core';
|
||||
import { Validators } from '@angular/forms';
|
||||
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Buffer } from 'buffer';
|
||||
import { Subscription, take } from 'rxjs';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { phoneValidator, requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { MetadataDialogComponent } from 'src/app/modules/metadata/metadata-dialog/metadata-dialog.component';
|
||||
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
|
||||
@@ -304,6 +306,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
descriptionKey: 'USER.LOGINMETHODS.PHONE.EDITDESC',
|
||||
value: this.user?.human?.phone?.phone,
|
||||
type: type,
|
||||
validator: Validators.compose([phoneValidator, requiredValidator]),
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
@@ -3,40 +3,39 @@
|
||||
</h1>
|
||||
<p class="desc cnsl-secondary-text">{{ data.descriptionKey | translate }}</p>
|
||||
<div mat-dialog-content>
|
||||
<div class="phone-grid">
|
||||
<cnsl-form-field *ngIf="isPhone">
|
||||
<cnsl-label>{{ 'USER.PROFILE.COUNTRY' | translate }}</cnsl-label>
|
||||
<mat-select [(value)]="selected" (selectionChange)="setCountryCallingCode()">
|
||||
<mat-select-trigger> <span class="fi fi-{{ selected?.countryCode | lowercase }}"></span></mat-select-trigger>
|
||||
<mat-option *ngFor="let country of countryPhoneCodes" [value]="country">
|
||||
<span class="fi fi-{{ country.countryCode | lowercase }}"></span>
|
||||
<span class="phone-country-name">{{ country.countryName }}</span>
|
||||
<span class="phone-country-code">+{{ country.countryCallingCode }}</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ data.labelKey | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
[formControl]="valueControl"
|
||||
matTooltip="{{ 'USER.PROFILE.PHONE_HINT' | translate }}"
|
||||
[matTooltipDisabled]="!isPhone"
|
||||
/>
|
||||
<span cnslError *ngIf="valueControl?.invalid && valueControl?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<form [formGroup]="dialogForm" (ngSubmit)="closeDialogWithValue()">
|
||||
<div class="phone-grid">
|
||||
<cnsl-form-field *ngIf="isPhone">
|
||||
<cnsl-label>{{ 'USER.PROFILE.COUNTRY' | translate }}</cnsl-label>
|
||||
<mat-select [(value)]="selected" (selectionChange)="setCountryCallingCode()">
|
||||
<mat-select-trigger> <span class="fi fi-{{ selected?.countryCode | lowercase }}"></span></mat-select-trigger>
|
||||
<mat-option *ngFor="let country of countryPhoneCodes" [value]="country">
|
||||
<span class="fi fi-{{ country.countryCode | lowercase }}"></span>
|
||||
<span class="phone-country-name">{{ country.countryName }}</span>
|
||||
<span class="phone-country-code">+{{ country.countryCallingCode }}</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ data.labelKey | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
[formControlName]="controlKey"
|
||||
matTooltip="{{ 'USER.PROFILE.PHONE_HINT' | translate }}"
|
||||
[matTooltipDisabled]="!isPhone"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-stroked-button class="ok-button" (click)="closeDialog()">
|
||||
@@ -44,7 +43,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
[disabled]="valueControl.invalid"
|
||||
[disabled]="dialogForm.invalid"
|
||||
cdkFocusInitial
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { KeyValuePipe } from '@angular/common';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { UntypedFormControl, Validators } from '@angular/forms';
|
||||
import { FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import {
|
||||
MatLegacyDialogRef as MatDialogRef,
|
||||
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
|
||||
} from '@angular/material/legacy-dialog';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { CountryCallingCodesService, CountryPhoneCode } from 'src/app/services/country-calling-codes.service';
|
||||
import { formatPhone } from 'src/app/utils/formatPhone';
|
||||
|
||||
@@ -13,15 +16,16 @@ export enum EditDialogType {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-edit-email-dialog',
|
||||
selector: 'cnsl-edit-dialog',
|
||||
templateUrl: './edit-dialog.component.html',
|
||||
styleUrls: ['./edit-dialog.component.scss'],
|
||||
})
|
||||
export class EditDialogComponent implements OnInit {
|
||||
public controlKey = 'editingField';
|
||||
public isPhone: boolean = false;
|
||||
public isVerified: boolean = false;
|
||||
public phoneCountry: string = 'CH';
|
||||
public valueControl: UntypedFormControl = new UntypedFormControl(['', [Validators.required]]);
|
||||
public dialogForm!: UntypedFormGroup;
|
||||
public EditDialogType: any = EditDialogType;
|
||||
public selected: CountryPhoneCode | undefined;
|
||||
public countryPhoneCodes: CountryPhoneCode[] = [];
|
||||
@@ -29,25 +33,33 @@ export class EditDialogComponent implements OnInit {
|
||||
public dialogRef: MatDialogRef<EditDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
private countryCallingCodesService: CountryCallingCodesService,
|
||||
private translateSvc: TranslateService,
|
||||
private kvPipe: KeyValuePipe,
|
||||
) {
|
||||
this.valueControl.setValue(data.value);
|
||||
if (data.type === EditDialogType.PHONE) {
|
||||
this.isPhone = true;
|
||||
}
|
||||
this.dialogForm = new FormGroup({
|
||||
[this.controlKey]: new UntypedFormControl(data.value, data.validator || requiredValidator),
|
||||
});
|
||||
}
|
||||
|
||||
public setCountryCallingCode(): void {
|
||||
let value = (this.valueControl?.value as string) || '';
|
||||
this.valueControl?.setValue('+' + this.selected?.countryCallingCode + ' ' + value.replace(/\+[0-9]*\s/, ''));
|
||||
console.log(this);
|
||||
let value = (this.dialogForm.controls[this.controlKey]?.value as string) || '';
|
||||
this.countryPhoneCodes.forEach((code) => (value = value.replace(`+${code.countryCallingCode}`, '')));
|
||||
value = value.trim();
|
||||
this.dialogForm.controls[this.controlKey]?.setValue('+' + this.selected?.countryCallingCode + ' ' + value);
|
||||
console.log(this);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.isPhone) {
|
||||
// Get country phone codes and set selected flag to guessed country or default country
|
||||
this.countryPhoneCodes = this.countryCallingCodesService.getCountryCallingCodes();
|
||||
const phoneNumber = formatPhone(this.valueControl?.value);
|
||||
const phoneNumber = formatPhone(this.dialogForm.controls[this.controlKey]?.value);
|
||||
this.selected = this.countryPhoneCodes.find((code) => code.countryCode === phoneNumber.country);
|
||||
this.valueControl.setValue(phoneNumber.phone);
|
||||
this.dialogForm.controls[this.controlKey].setValue(phoneNumber.phone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +68,10 @@ export class EditDialogComponent implements OnInit {
|
||||
}
|
||||
|
||||
closeDialogWithValue(): void {
|
||||
this.dialogRef.close({ value: this.valueControl.value, isVerified: this.isVerified });
|
||||
this.dialogRef.close({ value: this.dialogForm.controls[this.controlKey].value, isVerified: this.isVerified });
|
||||
}
|
||||
|
||||
public get ctrl() {
|
||||
return this.dialogForm.get(this.controlKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,10 @@
|
||||
<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>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { AccessTokenType, Human, Machine } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
|
||||
@Component({
|
||||
@@ -25,10 +26,10 @@ export class DetailFormMachineComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(private fb: UntypedFormBuilder) {
|
||||
this.machineForm = this.fb.group({
|
||||
userName: [{ value: '', disabled: true }, [Validators.required]],
|
||||
name: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
userName: [{ value: '', disabled: true }, [requiredValidator]],
|
||||
name: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
description: [{ value: '', disabled: this.disabled }],
|
||||
accessTokenType: [AccessTokenType.ACCESS_TOKEN_TYPE_BEARER, [Validators.required]],
|
||||
accessTokenType: [AccessTokenType.ACCESS_TOKEN_TYPE_BEARER, [requiredValidator]],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, OnDestroy, Output } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { Gender, Human, Profile } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
|
||||
import { ProfilePictureComponent } from './profile-picture/profile-picture.component';
|
||||
@@ -30,11 +31,11 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
|
||||
|
||||
constructor(private fb: UntypedFormBuilder, private dialog: MatDialog) {
|
||||
this.profileForm = this.fb.group({
|
||||
userName: [{ value: '', disabled: true }, [Validators.required]],
|
||||
firstName: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
lastName: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
userName: [{ value: '', disabled: true }, [requiredValidator]],
|
||||
firstName: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
lastName: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
nickName: [{ value: '', disabled: this.disabled }],
|
||||
displayName: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
displayName: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
gender: [{ value: 0, disabled: this.disabled }],
|
||||
preferredLanguage: [{ value: '', disabled: this.disabled }],
|
||||
});
|
||||
@@ -42,11 +43,11 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
|
||||
|
||||
public ngOnChanges(): void {
|
||||
this.profileForm = this.fb.group({
|
||||
userName: [{ value: '', disabled: true }, [Validators.required]],
|
||||
firstName: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
lastName: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
userName: [{ value: '', disabled: true }, [requiredValidator]],
|
||||
firstName: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
lastName: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
nickName: [{ value: '', disabled: this.disabled }],
|
||||
displayName: [{ value: '', disabled: this.disabled }, Validators.required],
|
||||
displayName: [{ value: '', disabled: this.disabled }, requiredValidator],
|
||||
gender: [{ value: 0, disabled: this.disabled }],
|
||||
preferredLanguage: [{ value: '', disabled: this.disabled }],
|
||||
});
|
||||
|
||||
@@ -17,17 +17,10 @@
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEW' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="password" formControlName="password" type="password" />
|
||||
|
||||
<span cnslError *ngIf="password?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="passwordRepeat" formControlName="confirmPassword" type="password" />
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
@@ -58,9 +51,6 @@
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.OLD' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="password" type="password" formControlName="currentPassword" />
|
||||
<span cnslError *ngIf="currentPassword?.errors?.required">
|
||||
{{ 'USER.PASSWORD.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="validation between" *ngIf="this.policy">
|
||||
@@ -71,10 +61,6 @@
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.NEW' | translate }}</cnsl-label>
|
||||
<input cnslInput autocomplete="off" name="new password" type="password" formControlName="newPassword" />
|
||||
|
||||
<span cnslError *ngIf="newPassword?.errors?.required">
|
||||
{{ 'USER.VALIDATION.REQUIRED' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</cnsl-label>
|
||||
@@ -85,9 +71,6 @@
|
||||
type="password"
|
||||
formControlName="confirmPassword"
|
||||
/>
|
||||
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
|
||||
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,28 +2,21 @@ import { Component, OnDestroy } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Subject, Subscription, take, takeUntil } from 'rxjs';
|
||||
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators';
|
||||
import {
|
||||
containsLowerCaseValidator,
|
||||
containsNumberValidator,
|
||||
containsSymbolValidator,
|
||||
containsUpperCaseValidator,
|
||||
minLengthValidator,
|
||||
passwordConfirmValidator,
|
||||
requiredValidator,
|
||||
} from 'src/app/modules/form-field/validators/validators';
|
||||
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
function passwordConfirmValidator(c: AbstractControl): any {
|
||||
if (!c.parent || !c) {
|
||||
return;
|
||||
}
|
||||
const pwd = c.parent.get('password');
|
||||
const cpwd = c.parent.get('confirmPassword');
|
||||
|
||||
if (!pwd || !cpwd) {
|
||||
return;
|
||||
}
|
||||
if (pwd.value !== cpwd.value) {
|
||||
return { invalid: true, notequal: 'Password is not equal' };
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-password',
|
||||
templateUrl: './password.component.html',
|
||||
@@ -76,7 +69,7 @@ export class PasswordComponent implements OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
const validators: Validators[] = [Validators.required];
|
||||
const validators: Validators[] = [requiredValidator];
|
||||
this.authService
|
||||
.getMyPasswordComplexityPolicy()
|
||||
.then((resp) => {
|
||||
@@ -84,19 +77,19 @@ export class PasswordComponent implements OnDestroy {
|
||||
this.policy = resp.policy;
|
||||
}
|
||||
if (this.policy.minLength) {
|
||||
validators.push(Validators.minLength(this.policy.minLength));
|
||||
validators.push(minLengthValidator(this.policy.minLength));
|
||||
}
|
||||
if (this.policy.hasLowercase) {
|
||||
validators.push(lowerCaseValidator);
|
||||
validators.push(containsLowerCaseValidator);
|
||||
}
|
||||
if (this.policy.hasUppercase) {
|
||||
validators.push(upperCaseValidator);
|
||||
validators.push(containsUpperCaseValidator);
|
||||
}
|
||||
if (this.policy.hasNumber) {
|
||||
validators.push(numberValidator);
|
||||
validators.push(containsNumberValidator);
|
||||
}
|
||||
if (this.policy.hasSymbol) {
|
||||
validators.push(symbolValidator);
|
||||
validators.push(containsSymbolValidator);
|
||||
}
|
||||
|
||||
this.setupForm(validators);
|
||||
@@ -117,13 +110,13 @@ export class PasswordComponent implements OnDestroy {
|
||||
if (this.userId) {
|
||||
this.passwordForm = this.fb.group({
|
||||
password: ['', validators],
|
||||
confirmPassword: ['', [...validators, passwordConfirmValidator]],
|
||||
confirmPassword: ['', [requiredValidator, passwordConfirmValidator()]],
|
||||
});
|
||||
} else {
|
||||
this.passwordForm = this.fb.group({
|
||||
currentPassword: ['', Validators.required],
|
||||
currentPassword: ['', requiredValidator],
|
||||
newPassword: ['', validators],
|
||||
confirmPassword: ['', [...validators, passwordConfirmValidator]],
|
||||
confirmPassword: ['', [requiredValidator, passwordConfirmValidator()]],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { MediaMatcher } from '@angular/cdk/layout';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, EventEmitter, OnInit } from '@angular/core';
|
||||
import { Validators } from '@angular/forms';
|
||||
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Buffer } from 'buffer';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { phoneValidator, requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
|
||||
import { MetadataDialogComponent } from 'src/app/modules/metadata/metadata-dialog/metadata-dialog.component';
|
||||
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
|
||||
@@ -461,6 +463,7 @@ export class UserDetailComponent implements OnInit {
|
||||
descriptionKey: 'USER.LOGINMETHODS.PHONE.EDITDESC',
|
||||
value: this.user.human?.phone?.phone,
|
||||
type: EditDialogType.PHONE,
|
||||
validator: Validators.compose([phoneValidator, requiredValidator]),
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
|
||||
export function symbolValidator(c: UntypedFormControl): any {
|
||||
const REGEXP: RegExp = /[^a-z0-9]/gi;
|
||||
|
||||
return REGEXP.test(c.value)
|
||||
? null
|
||||
: {
|
||||
invalid: true,
|
||||
symbolValidator: {
|
||||
valid: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function numberValidator(c: UntypedFormControl): any {
|
||||
const REGEXP = /[0-9]/g;
|
||||
|
||||
return REGEXP.test(c.value)
|
||||
? null
|
||||
: {
|
||||
invalid: true,
|
||||
numberValidator: {
|
||||
valid: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function upperCaseValidator(c: UntypedFormControl): any {
|
||||
const REGEXP = /[A-Z]/g;
|
||||
|
||||
return REGEXP.test(c.value)
|
||||
? null
|
||||
: {
|
||||
invalid: true,
|
||||
upperCaseValidator: {
|
||||
valid: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function lowerCaseValidator(c: UntypedFormControl): any {
|
||||
const REGEXP = /[a-z]/g;
|
||||
|
||||
return REGEXP.test(c.value)
|
||||
? null
|
||||
: {
|
||||
invalid: true,
|
||||
lowerCaseValidator: {
|
||||
valid: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user