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 <[email protected]>
This commit is contained in:
Elio Bischof
2023-03-14 21:29:45 +00:00
committed by GitHub
co-authored by Max Peintner
parent e00cc187fa
commit 93e1fe0056
50 changed files with 504 additions and 535 deletions
@@ -0,0 +1,20 @@
<div class="cnsl-form-field-wrapper" (click)="_control.onContainerClick && _control.onContainerClick($event)">
<ng-content select="cnsl-label"></ng-content>
<div class="cnsl-rel" #inputContainer>
<ng-content></ng-content>
<ng-content select="cnslSuffix"></ng-content>
</div>
<ng-container *ngIf="help$ && help$ | async as help">
<div [ngSwitch]="help.type" class="cnsl-form-field-subscript-wrapper">
<div *ngSwitchCase="'hints'" class="cnsl-form-field-hint-wrapper" [@transitionMessages]="_subscriptAnimationState">
<ng-content select="cnsl-hint"></ng-content>
</div>
<div *ngSwitchCase="'errors'" class="cnsl-form-field-error-wrapper" [@transitionMessages]="_subscriptAnimationState">
<span cnslError *ngFor="let err of help.validationErrors">
{{ err.i18nKey | translate : err.params }}
</span>
<ng-content select="cnsl-error"></ng-content>
</div>
</div>
</ng-container>
</div>
@@ -10,6 +10,7 @@ import {
HostListener,
Inject,
InjectionToken,
Input,
OnDestroy,
QueryList,
ViewChild,
@@ -17,11 +18,10 @@ import {
} from '@angular/core';
import { NgControl } from '@angular/forms';
import { MatLegacyFormFieldControl as MatFormFieldControl } from '@angular/material/legacy-form-field';
import { Subject } from 'rxjs';
import { startWith, takeUntil } from 'rxjs/operators';
import { combineLatest, map, Observable, of, startWith, Subject, takeUntil } from 'rxjs';
import { CnslErrorDirective, CNSL_ERROR } from '../error/error.directive';
import { cnslFormFieldAnimations } from './animations';
import { CnslErrorDirective, CNSL_ERROR } from './error.directive';
export const CNSL_FORM_FIELD = new InjectionToken<CnslFormFieldComponent>('CnslFormFieldComponent');
@@ -29,6 +29,15 @@ class CnslFormFieldBase {
constructor(public _elementRef: ElementRef) {}
}
interface Help {
type: 'hints' | 'errors';
validationErrors?: Array<ValidationError>;
}
interface ValidationError {
i18nKey: string;
params: any;
}
@Component({
selector: 'cnsl-form-field',
templateUrl: './form-field.component.html',
@@ -59,19 +68,24 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
@ViewChild('inputContainer') _inputContainerRef!: ElementRef;
@ContentChild(MatFormFieldControl) _controlNonStatic!: MatFormFieldControl<any>;
@ContentChild(MatFormFieldControl, { static: true }) _controlStatic!: MatFormFieldControl<any>;
@Input() public disableValidationErrors = false;
get _control(): MatFormFieldControl<any> {
return this._explicitFormFieldControl || this._controlNonStatic || this._controlStatic;
}
set _control(value: MatFormFieldControl<any>) {
this._explicitFormFieldControl = value;
}
private _explicitFormFieldControl!: MatFormFieldControl<any>;
readonly stateChanges: Subject<void> = new Subject<void>();
public help$?: Observable<Help>;
_subscriptAnimationState: string = '';
@ContentChildren(CNSL_ERROR as any, { descendants: true }) _errorChildren!: QueryList<CnslErrorDirective>;
// TODO: Remove?
@HostListener('blur', ['false'])
_focusChanged(isFocused: boolean): void {
if (isFocused !== this.focused && !isFocused) {
@@ -91,8 +105,6 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
}
public ngAfterViewInit(): void {
// Avoid animations on load.
this._subscriptAnimationState = 'enter';
this._changeDetectorRef.detectChanges();
}
@@ -103,25 +115,21 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
public ngAfterContentInit(): void {
this._validateControlChild();
this.mapHelp();
const control = this._control;
control.stateChanges.pipe(startWith(null)).subscribe(() => {
control.stateChanges.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
this._syncDescribedByIds();
this._changeDetectorRef.markForCheck();
});
// Run change detection if the value changes.
// TODO: Is that not redundant (see immediately above)?
if (control.ngControl && control.ngControl.valueChanges) {
control.ngControl.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(() => this._changeDetectorRef.markForCheck());
}
// Update the aria-described by when the number of errors changes.
this._errorChildren.changes.pipe(startWith(null)).subscribe(() => {
this._syncDescribedByIds();
this._changeDetectorRef.markForCheck();
});
}
/** Throws an error if the form field's control is missing. */
@@ -147,14 +155,68 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
}
}
private mapHelp(): void {
const validationErrors$: Observable<Array<ValidationError>> = this.disableValidationErrors
? of([])
: this._control.stateChanges?.pipe(
map(() => this.currentValidationErrors()),
startWith([]),
) || of([]);
const childrenErrors$: Observable<boolean> = this._errorChildren.changes.pipe(
map(() => {
return this._errorChildren.length > 0;
}),
startWith(false),
);
this.help$ = combineLatest([validationErrors$, childrenErrors$]).pipe(
map((combined) => {
return combined[0].length >= 1
? <Help>{
type: 'errors',
validationErrors: combined[0],
}
: combined[1]
? <Help>{
type: 'errors',
}
: <Help>{
type: 'hints',
validationErrors: undefined,
};
}),
);
this._changeDetectorRef.markForCheck();
}
private currentValidationErrors(): Array<ValidationError> {
return (
Object.entries(this._control.ngControl?.control?.errors || [])
?.filter(this.filterErrorsProperties)
.map(this.mapToValidationError)
.filter(this.distinctFilter) || []
);
}
private filterErrorsProperties(kv: [string, any]): boolean {
return typeof kv[1] == 'object' && (kv[1] as { valid: boolean }).valid === false;
}
private mapToValidationError(kv: [string, any]): ValidationError {
return {
i18nKey: 'ERRORS.INVALID_FORMAT',
...(kv[1] as ValidationError | any),
};
}
private distinctFilter(_: ValidationError, index: number, arr: Array<ValidationError>): boolean {
return arr.findIndex((item) => item.i18nKey) === index;
}
/** Determines whether a class from the NgControl should be forwarded to the host element. */
_shouldForward(prop: keyof NgControl): boolean {
const ngControl: any = this._control ? this._control.ngControl : null;
return ngControl && ngControl[prop];
}
/** Determines whether to display hints or errors. */
_getDisplayedMessages(): 'error' | 'hint' {
return this._errorChildren && this._errorChildren.length > 0 ? 'error' : 'hint';
}
}
@@ -1,15 +0,0 @@
<div class="cnsl-form-field-wrapper" (click)="_control.onContainerClick && _control.onContainerClick($event)">
<ng-content select="cnsl-label"></ng-content>
<div class="cnsl-rel" #inputContainer>
<ng-content></ng-content>
<ng-content select="cnslSuffix"></ng-content>
</div>
<div class="cnsl-form-field-subscript-wrapper" [ngSwitch]="_getDisplayedMessages()">
<div *ngSwitchCase="'error'" class="cnsl-form-field-error-wrapper" [@transitionMessages]="_subscriptAnimationState">
<ng-content select="cnsl-error"></ng-content>
</div>
<div *ngSwitchCase="'hint'" class="cnsl-form-field-hint-wrapper" [@transitionMessages]="_subscriptAnimationState">
<ng-content select="cnsl-hint"></ng-content>
</div>
</div>
</div>
@@ -1,15 +1,16 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatRippleModule } from '@angular/material/core';
import { TranslateModule } from '@ngx-translate/core';
import { LabelModule } from 'src/app/modules/label/label.module';
import { LabelComponent } from '../label/label.component';
import { CnslErrorDirective } from './error.directive';
import { CnslFormFieldComponent } from './form-field.component';
import { CnslErrorDirective } from './error/error.directive';
import { CnslFormFieldComponent } from './field/form-field.component';
@NgModule({
declarations: [CnslFormFieldComponent, CnslErrorDirective],
imports: [CommonModule, MatRippleModule, LabelModule],
imports: [CommonModule, MatRippleModule, LabelModule, TranslateModule],
exports: [CnslFormFieldComponent, LabelComponent, CnslErrorDirective],
})
export class FormFieldModule {}
@@ -0,0 +1,73 @@
import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
export function containsSymbolValidator(c: AbstractControl): ValidationErrors | null {
return regexpValidator(c, /[^a-z0-9]/gi, 'ERRORS.SYMBOLERROR');
}
export function containsNumberValidator(c: AbstractControl): ValidationErrors | null {
return regexpValidator(c, /[0-9]/g, 'ERRORS.NUMBERERROR');
}
export function containsUpperCaseValidator(c: AbstractControl): ValidationErrors | null {
return regexpValidator(c, /[A-Z]/g, 'ERRORS.UPPERCASEMISSING');
}
export function containsLowerCaseValidator(c: AbstractControl): ValidationErrors | null {
return regexpValidator(c, /[a-z]/g, 'ERRORS.LOWERCASEMISSING');
}
export function phoneValidator(c: AbstractControl): ValidationErrors | null {
return regexpValidator(c, /^($|(\+|00)[0-9 ]+$)/, 'ERRORS.PHONE');
}
export function requiredValidator(c: AbstractControl): ValidationErrors | null {
return i18nErr(Validators.required(c), 'ERRORS.REQUIRED');
}
export function emailValidator(c: AbstractControl): ValidationErrors | null {
return i18nErr(Validators.email(c), 'ERRORS.NOTANEMAIL');
}
export function minLengthValidator(minLength: number): ValidatorFn {
return (c: AbstractControl): ValidationErrors | null => {
return i18nErr(Validators.minLength(minLength)(c), 'ERRORS.MINLENGTH', { requiredLength: minLength });
};
}
export function passwordConfirmValidator(passwordControlName: string = 'password') {
return (c: AbstractControl): ValidationErrors | null => {
if (!c.parent || !c) {
return null;
}
const pwd = c.parent.get(passwordControlName);
const cpwd = c;
if (!pwd || !cpwd) {
return null;
}
if (pwd.value !== cpwd.value) {
return i18nErr(undefined, 'ERRORS.PWNOTEQUAL');
}
return null;
};
}
function regexpValidator(c: AbstractControl, regexp: RegExp, i18nKey: string): ValidationErrors | null {
return !c.value || regexp.test(c.value) ? null : i18nErr({ invalid: true }, i18nKey, { regexp: regexp });
}
function i18nErr(err: ValidationErrors | null | undefined, i18nKey: string, params?: any): ValidationErrors | null {
if (err === null) {
return null;
} else {
return {
...err,
invalid: true,
[i18nKey.toLowerCase().replaceAll('.', '')]: {
valid: false,
i18nKey: i18nKey,
params: params,
},
};
}
}
@@ -28,23 +28,23 @@
</span>
</div>
<div class="val" *ngIf="this.policy.hasSymbol">
<i *ngIf="password?.errors?.symbolValidator" class="las la-times red"></i>
<i *ngIf="!password?.errors?.symbolValidator" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'USER.VALIDATION.SYMBOLERROR' | translate }}</span>
<i *ngIf="password?.pristine || password?.errors?.errorssymbolerror" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.errorssymbolerror" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'ERRORS.SYMBOLERROR' | translate }}</span>
</div>
<div class="val" *ngIf="this.policy.hasNumber">
<i *ngIf="password?.errors?.numberValidator" class="las la-times red"></i>
<i *ngIf="!password?.errors?.numberValidator" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'USER.VALIDATION.NUMBERERROR' | translate }}</span>
<i *ngIf="password?.pristine || password?.errors?.errorsnumbererror" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.errorsnumbererror" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'ERRORS.NUMBERERROR' | translate }}</span>
</div>
<div class="val" *ngIf="this.policy.hasUppercase">
<i *ngIf="password?.errors?.upperCaseValidator" class="las la-times red"></i>
<i *ngIf="!password?.errors?.upperCaseValidator" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}</span>
<i *ngIf="password?.pristine || password?.errors?.errorsuppercasemissing" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.errorsuppercasemissing" class="las la-check green"></i>
<span class="cnsl-secondary-text"> {{ 'ERRORS.UPPERCASEMISSING' | translate }}</span>
</div>
<div class="val" *ngIf="this.policy.hasLowercase">
<i *ngIf="password?.errors?.lowerCaseValidator" class="las la-times red"></i>
<i *ngIf="!password?.errors?.lowerCaseValidator" class="las la-check green"></i>
<span class="cnsl-secondary-text">{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}</span>
<i *ngIf="password?.pristine || password?.errors?.errorslowercasemissing" class="las la-times red"></i>
<i *ngIf="password?.dirty && !password?.errors?.errorslowercasemissing" class="las la-check green"></i>
<span class="cnsl-secondary-text">{{ 'ERRORS.LOWERCASEMISSING' | translate }}</span>
</div>
</div>
@@ -1,5 +1,5 @@
import { Component, Injector, Input, OnInit, Type } 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 { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { take } from 'rxjs';
@@ -18,6 +18,7 @@ import { AdminService } from 'src/app/services/admin.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';
import { requiredValidator } from '../../form-field/validators/validators';
import { InfoSectionType } from '../../info-section/info-section.component';
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
@@ -45,11 +46,11 @@ export class LoginPolicyComponent implements OnInit {
public InfoSectionType: any = InfoSectionType;
public PasswordlessType: any = PasswordlessType;
public lifetimeForm: UntypedFormGroup = this.fb.group({
passwordCheckLifetime: [{ disabled: true }, [Validators.required]],
externalLoginCheckLifetime: [{ disabled: true }, [Validators.required]],
mfaInitSkipLifetime: [{ disabled: true }, [Validators.required]],
secondFactorCheckLifetime: [{ disabled: true }, [Validators.required]],
multiFactorCheckLifetime: [{ disabled: true }, [Validators.required]],
passwordCheckLifetime: [{ disabled: true }, [requiredValidator]],
externalLoginCheckLifetime: [{ disabled: true }, [requiredValidator]],
mfaInitSkipLifetime: [{ disabled: true }, [requiredValidator]],
secondFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
multiFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
});
constructor(
private toast: ToastService,
@@ -1,10 +1,11 @@
import { Component, Inject } from '@angular/core';
import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import {
MatLegacyDialog as MatDialog,
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 {
AddSMSProviderTwilioRequest,
UpdateSMSProviderTwilioRequest,
@@ -44,15 +45,15 @@ export class DialogAddSMSProviderComponent {
@Inject(MAT_DIALOG_DATA) public data: any,
) {
this.twilioForm = this.fb.group({
sid: ['', [Validators.required]],
senderNumber: ['', [Validators.required]],
sid: ['', [requiredValidator]],
senderNumber: ['', [requiredValidator]],
});
this.smsProviders = data.smsProviders;
if (!!this.twilio) {
this.twilioForm.patchValue(this.twilio);
} else {
this.twilioForm.addControl('token', new FormControl('', Validators.required));
this.twilioForm.addControl('token', new FormControl('', requiredValidator));
}
}
@@ -1,5 +1,5 @@
import { Component, Input, OnInit } 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 { take } from 'rxjs';
import {
@@ -15,6 +15,7 @@ import { DebugNotificationProvider, SMSProvider, SMSProviderConfigState } from '
import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { InfoSectionType } from '../../info-section/info-section.component';
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
@@ -55,11 +56,11 @@ export class NotificationSettingsComponent implements OnInit {
private authService: GrpcAuthService,
) {
this.form = this.fb.group({
senderAddress: [{ disabled: true, value: '' }, [Validators.required]],
senderName: [{ disabled: true, value: '' }, [Validators.required]],
tls: [{ disabled: true, value: true }, [Validators.required]],
hostAndPort: [{ disabled: true, value: '' }, [Validators.required]],
user: [{ disabled: true, value: '' }, [Validators.required]],
senderAddress: [{ disabled: true, value: '' }, [requiredValidator]],
senderName: [{ disabled: true, value: '' }, [requiredValidator]],
tls: [{ disabled: true, value: true }, [requiredValidator]],
hostAndPort: [{ disabled: true, value: '' }, [requiredValidator]],
user: [{ disabled: true, value: '' }, [requiredValidator]],
});
}
@@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { take } from 'rxjs';
import {
@@ -12,6 +12,7 @@ import { OIDCSettings } from 'src/app/proto/generated/zitadel/settings_pb';
import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
@Component({
selector: 'cnsl-oidc-configuration',
@@ -31,10 +32,10 @@ export class OIDCConfigurationComponent implements OnInit {
private authService: GrpcAuthService,
) {
this.form = this.fb.group({
accessTokenLifetime: [{ disabled: true }, [Validators.required]],
idTokenLifetime: [{ disabled: true }, [Validators.required]],
refreshTokenExpiration: [{ disabled: true }, [Validators.required]],
refreshTokenIdleExpiration: [{ disabled: true }, [Validators.required]],
accessTokenLifetime: [{ disabled: true }, [requiredValidator]],
idTokenLifetime: [{ disabled: true }, [requiredValidator]],
refreshTokenExpiration: [{ disabled: true }, [requiredValidator]],
refreshTokenIdleExpiration: [{ disabled: true }, [requiredValidator]],
});
}
@@ -1,10 +1,11 @@
import { Component, Inject } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import {
MatLegacyDialogRef as MatDialogRef,
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
} from '@angular/material/legacy-dialog';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
import { UpdateSecretGeneratorRequest } from 'src/app/proto/generated/zitadel/admin_pb';
import { SecretGeneratorType } from 'src/app/proto/generated/zitadel/settings_pb';
@@ -33,13 +34,13 @@ export class DialogAddSecretGeneratorComponent {
@Inject(MAT_DIALOG_DATA) public data: any,
) {
this.specsForm = this.fb.group({
generatorType: [SecretGeneratorType.SECRET_GENERATOR_TYPE_APP_SECRET, [Validators.required]],
expiry: [1, [Validators.required]],
includeDigits: [true, [Validators.required]],
includeLowerLetters: [true, [Validators.required]],
includeSymbols: [true, [Validators.required]],
includeUpperLetters: [true, [Validators.required]],
length: [6, [Validators.required]],
generatorType: [SecretGeneratorType.SECRET_GENERATOR_TYPE_APP_SECRET, [requiredValidator]],
expiry: [1, [requiredValidator]],
includeDigits: [true, [requiredValidator]],
includeLowerLetters: [true, [requiredValidator]],
includeSymbols: [true, [requiredValidator]],
includeUpperLetters: [true, [requiredValidator]],
length: [6, [requiredValidator]],
});
this.generatorType?.setValue(data.type);
@@ -1,11 +1,12 @@
import { Component, Inject } from '@angular/core';
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import {
MatLegacyDialogRef as MatDialogRef,
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
} from '@angular/material/legacy-dialog';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../form-field/validators/validators';
@Component({
selector: 'cnsl-project-role-detail-dialog',
@@ -24,7 +25,7 @@ export class ProjectRoleDetailDialogComponent {
) {
this.projectId = data.projectId;
this.formGroup = new UntypedFormGroup({
key: new UntypedFormControl({ value: '', disabled: true }, [Validators.required]),
key: new UntypedFormControl({ value: '', disabled: true }, [requiredValidator]),
displayName: new UntypedFormControl(''),
group: new UntypedFormControl(''),
});
@@ -1,7 +1,7 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component, Injector, Type } from '@angular/core';
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs';
@@ -20,6 +20,7 @@ import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -51,12 +52,12 @@ export class ProviderGithubESComponent {
breadcrumbService: BreadcrumbService,
) {
this.form = new UntypedFormGroup({
name: new UntypedFormControl('', [Validators.required]),
clientId: new UntypedFormControl('', [Validators.required]),
clientSecret: new UntypedFormControl('', [Validators.required]),
authorizationEndpoint: new UntypedFormControl('', [Validators.required]),
tokenEndpoint: new UntypedFormControl('', [Validators.required]),
userEndpoint: new UntypedFormControl('', [Validators.required]),
name: new UntypedFormControl('', [requiredValidator]),
clientId: new UntypedFormControl('', [requiredValidator]),
clientSecret: new UntypedFormControl('', [requiredValidator]),
authorizationEndpoint: new UntypedFormControl('', [requiredValidator]),
tokenEndpoint: new UntypedFormControl('', [requiredValidator]),
userEndpoint: new UntypedFormControl('', [requiredValidator]),
scopesList: new UntypedFormControl(['openid', 'profile', 'email'], []),
});
@@ -1,7 +1,7 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component, Injector, Type } from '@angular/core';
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs';
@@ -20,6 +20,7 @@ import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -53,8 +54,8 @@ export class ProviderGithubComponent {
) {
this.form = new FormGroup({
name: new FormControl('', []),
clientId: new FormControl('', [Validators.required]),
clientSecret: new FormControl('', [Validators.required]),
clientId: new FormControl('', [requiredValidator]),
clientSecret: new FormControl('', [requiredValidator]),
scopesList: new FormControl(['openid', 'profile', 'email'], []),
});
@@ -1,7 +1,7 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component, Injector, Type } from '@angular/core';
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs';
@@ -20,6 +20,7 @@ import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -53,8 +54,8 @@ export class ProviderGoogleComponent {
) {
this.form = new FormGroup({
name: new FormControl('', []),
clientId: new FormControl('', [Validators.required]),
clientSecret: new FormControl('', [Validators.required]),
clientId: new FormControl('', [requiredValidator]),
clientSecret: new FormControl('', [requiredValidator]),
scopesList: new FormControl(['openid', 'profile', 'email'], []),
});
@@ -1,7 +1,7 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component, Injector, Type } from '@angular/core';
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs/operators';
import {
@@ -19,6 +19,7 @@ import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -82,11 +83,11 @@ export class ProviderJWTComponent {
});
this.form = new UntypedFormGroup({
name: new UntypedFormControl('', [Validators.required]),
headerName: new UntypedFormControl('', [Validators.required]),
issuer: new UntypedFormControl('', [Validators.required]),
jwtEndpoint: new UntypedFormControl('', [Validators.required]),
keysEndpoint: new UntypedFormControl('', [Validators.required]),
name: new UntypedFormControl('', [requiredValidator]),
headerName: new UntypedFormControl('', [requiredValidator]),
issuer: new UntypedFormControl('', [requiredValidator]),
jwtEndpoint: new UntypedFormControl('', [requiredValidator]),
keysEndpoint: new UntypedFormControl('', [requiredValidator]),
});
}
@@ -1,7 +1,7 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component, Injector, Type } from '@angular/core';
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
import { ActivatedRoute, Router } from '@angular/router';
import { take } from 'rxjs';
@@ -20,6 +20,7 @@ import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -52,13 +53,13 @@ export class ProviderOAuthComponent {
breadcrumbService: BreadcrumbService,
) {
this.form = new UntypedFormGroup({
name: new UntypedFormControl('', [Validators.required]),
clientId: new UntypedFormControl('', [Validators.required]),
clientSecret: new UntypedFormControl('', [Validators.required]),
authorizationEndpoint: new UntypedFormControl('', [Validators.required]),
tokenEndpoint: new UntypedFormControl('', [Validators.required]),
userEndpoint: new UntypedFormControl('', [Validators.required]),
idAttribute: new UntypedFormControl('', [Validators.required]),
name: new UntypedFormControl('', [requiredValidator]),
clientId: new UntypedFormControl('', [requiredValidator]),
clientSecret: new UntypedFormControl('', [requiredValidator]),
authorizationEndpoint: new UntypedFormControl('', [requiredValidator]),
tokenEndpoint: new UntypedFormControl('', [requiredValidator]),
userEndpoint: new UntypedFormControl('', [requiredValidator]),
idAttribute: new UntypedFormControl('', [requiredValidator]),
scopesList: new UntypedFormControl(['openid', 'profile', 'email'], []),
});
@@ -1,7 +1,7 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component, Injector, Type } from '@angular/core';
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs';
@@ -20,6 +20,7 @@ import { AdminService } from 'src/app/services/admin.service';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -51,10 +52,10 @@ export class ProviderOIDCComponent {
breadcrumbService: BreadcrumbService,
) {
this.oidcFormGroup = new UntypedFormGroup({
name: new UntypedFormControl('', [Validators.required]),
clientId: new UntypedFormControl('', [Validators.required]),
clientSecret: new UntypedFormControl('', [Validators.required]),
issuer: new UntypedFormControl('', [Validators.required]),
name: new UntypedFormControl('', [requiredValidator]),
clientId: new UntypedFormControl('', [requiredValidator]),
clientSecret: new UntypedFormControl('', [requiredValidator]),
issuer: new UntypedFormControl('', [requiredValidator]),
scopesList: new UntypedFormControl(['openid', 'profile', 'email'], []),
});