From c420de1533090b11e1406f47131e32964d8f0e5f Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Tue, 18 Apr 2023 17:37:26 +0200 Subject: [PATCH] fix(console): LDAP UI optimization for better required field recognition, improve onboarding all done visibility (#5659) * fix: onboarding all done styles * ldap UI change * rm log * set required marker to formfield, max width of string-list comp * seperate formfields * formarray * clear action * validator * hide pwd field * rm dead code * lint --- .../field/form-field.component.html | 11 +- .../form-field/field/form-field.component.ts | 2 + .../form-field/validators/validators.ts | 12 ++ .../app/modules/label/label.component.scss | 16 ++- .../onboarding/onboarding.component.scss | 6 + .../ldap-attributes.component.html | 111 ++++++++++-------- .../ldap-attributes.component.scss | 5 + .../ldap-attributes.component.ts | 1 + .../provider-ldap.component.html | 36 +++--- .../provider-ldap/provider-ldap.component.ts | 35 ++++-- .../src/app/modules/providers/providers.scss | 15 +++ .../string-list/string-list.component.html | 67 ++++++----- .../string-list/string-list.component.scss | 70 +++++------ .../string-list/string-list.component.ts | 65 +++++----- .../modules/string-list/string-list.module.ts | 2 + .../user-create-machine.component.html | 4 +- .../user-create/user-create.component.html | 8 +- console/src/assets/i18n/de.json | 1 + console/src/assets/i18n/en.json | 1 + console/src/assets/i18n/es.json | 1 + console/src/assets/i18n/fr.json | 1 + console/src/assets/i18n/it.json | 1 + console/src/assets/i18n/ja.json | 1 + console/src/assets/i18n/pl.json | 1 + console/src/assets/i18n/zh.json | 1 + 25 files changed, 277 insertions(+), 197 deletions(-) diff --git a/console/src/app/modules/form-field/field/form-field.component.html b/console/src/app/modules/form-field/field/form-field.component.html index 376dbc229a..245bc57f80 100644 --- a/console/src/app/modules/form-field/field/form-field.component.html +++ b/console/src/app/modules/form-field/field/form-field.component.html @@ -1,5 +1,14 @@ + + + +
- +
diff --git a/console/src/app/modules/form-field/field/form-field.component.ts b/console/src/app/modules/form-field/field/form-field.component.ts index fd8e4a23af..804b44fb61 100644 --- a/console/src/app/modules/form-field/field/form-field.component.ts +++ b/console/src/app/modules/form-field/field/form-field.component.ts @@ -51,6 +51,7 @@ interface ValidationError { '[class.ng-valid]': '_shouldForward("valid")', '[class.ng-invalid]': '_shouldForward("invalid")', '[class.ng-pending]': '_shouldForward("pending")', + '[class.ng-required]': '_control.required', '[class.cnsl-form-field-disabled]': '_control.disabled', '[class.cnsl-form-field-autofilled]': '_control.autofilled', '[class.cnsl-focused]': '_control.focused', @@ -69,6 +70,7 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr @ContentChild(MatFormFieldControl) _controlNonStatic!: MatFormFieldControl; @ContentChild(MatFormFieldControl, { static: true }) _controlStatic!: MatFormFieldControl; @Input() public disableValidationErrors = false; + @Input() public hideRequiredMarker = false; get _control(): MatFormFieldControl { return this._explicitFormFieldControl || this._controlNonStatic || this._controlStatic; diff --git a/console/src/app/modules/form-field/validators/validators.ts b/console/src/app/modules/form-field/validators/validators.ts index 9c89699f42..d3661d0dc6 100644 --- a/console/src/app/modules/form-field/validators/validators.ts +++ b/console/src/app/modules/form-field/validators/validators.ts @@ -24,6 +24,12 @@ export function requiredValidator(c: AbstractControl): ValidationErrors | null { return i18nErr(Validators.required(c), 'ERRORS.REQUIRED'); } +export function minArrayLengthValidator(minArrLength: number): ValidatorFn { + return (c: AbstractControl): ValidationErrors | null => { + return arrayLengthValidator(c, minArrLength, 'ERRORS.ATLEASTONE'); + }; +} + export function emailValidator(c: AbstractControl): ValidationErrors | null { return i18nErr(Validators.email(c), 'ERRORS.NOTANEMAIL'); } @@ -56,6 +62,12 @@ function regexpValidator(c: AbstractControl, regexp: RegExp, i18nKey: string): V return !c.value || regexp.test(c.value) ? null : i18nErr({ invalid: true }, i18nKey, { regexp: regexp }); } +function arrayLengthValidator(c: AbstractControl, length: number, i18nKey: string): ValidationErrors | null { + const arr: string[] = c.value; + const invalidStrings: string[] = arr.filter((val: string) => val.trim() === ''); + return arr && invalidStrings.length === 0 && arr.length >= length ? null : i18nErr({ invalid: true }, i18nKey); +} + function i18nErr(err: ValidationErrors | null | undefined, i18nKey: string, params?: any): ValidationErrors | null { if (err === null) { return null; diff --git a/console/src/app/modules/label/label.component.scss b/console/src/app/modules/label/label.component.scss index 684b7b217f..f4046d4866 100644 --- a/console/src/app/modules/label/label.component.scss +++ b/console/src/app/modules/label/label.component.scss @@ -9,23 +9,31 @@ $foreground: map-get($theme, foreground); $secondary-text: map-get($foreground, secondary-text); - .cnsl-label { - display: block; + .cnsl-label-wrapper { + display: flex; font-size: 12px; color: $secondary-text; transition: color 0.2s ease; margin-bottom: 4px; font-weight: 400; + + .cnsl-label { + display: block; + } + + .cnsl-form-field-required-marker { + margin-left: 1px; + } } .cnsl-form-field-disabled { - .cnsl-label { + .cnsl-label-wrapper { color: if($is-dark-theme, #ffffff80, #00000061); } } .cnsl-form-field-invalid { - .cnsl-label { + .cnsl-label-wrapper { color: $warn-color; } } diff --git a/console/src/app/modules/onboarding/onboarding.component.scss b/console/src/app/modules/onboarding/onboarding.component.scss index 23872223d5..09a692ed6f 100644 --- a/console/src/app/modules/onboarding/onboarding.component.scss +++ b/console/src/app/modules/onboarding/onboarding.component.scss @@ -198,6 +198,12 @@ .state-circle { display: none; } + + .action-card { + .action-content { + opacity: 1; + } + } } } } diff --git a/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.html b/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.html index c119460860..5333825709 100644 --- a/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.html +++ b/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.html @@ -1,54 +1,65 @@
- {{ 'IDP.LDAPIDATTRIBUTE' | translate }}* - - - - {{ 'IDP.AVATARURLATTRIBUTE' | translate }} - - - - {{ 'IDP.DISPLAYNAMEATTRIBUTE' | translate }} - - - - {{ 'IDP.EMAILATTRIBUTEATTRIBUTE' | translate }} - - - - {{ 'IDP.EMAILVERIFIEDATTRIBUTE' | translate }} - - - - {{ 'IDP.FIRSTNAMEATTRIBUTE' | translate }} - - - - {{ 'IDP.LASTNAMEATTRIBUTE' | translate }} - - - - {{ 'IDP.NICKNAMEATTRIBUTE' | translate }} - - - - {{ 'IDP.PHONEATTRIBUTE' | translate }} - - - - {{ 'IDP.PHONEVERIFIEDATTRIBUTE' | translate }} - - - - {{ 'IDP.PREFERREDLANGUAGEATTRIBUTE' | translate }} - - - - {{ 'IDP.PREFERREDUSERNAMEATTRIBUTE' | translate }} - - - - {{ 'IDP.PROFILEATTRIBUTE' | translate }} - + {{ 'IDP.LDAPIDATTRIBUTE' | translate }} + + +
+ {{ 'ACTIONS.MORE' | translate }} + +
+ + + + {{ 'IDP.AVATARURLATTRIBUTE' | translate }} + + + + {{ 'IDP.DISPLAYNAMEATTRIBUTE' | translate }} + + + + {{ 'IDP.EMAILATTRIBUTEATTRIBUTE' | translate }} + + + + {{ 'IDP.EMAILVERIFIEDATTRIBUTE' | translate }} + + + + {{ 'IDP.FIRSTNAMEATTRIBUTE' | translate }} + + + + {{ 'IDP.LASTNAMEATTRIBUTE' | translate }} + + + + {{ 'IDP.NICKNAMEATTRIBUTE' | translate }} + + + + {{ 'IDP.PHONEATTRIBUTE' | translate }} + + + + {{ 'IDP.PHONEVERIFIEDATTRIBUTE' | translate }} + + + + {{ 'IDP.PREFERREDLANGUAGEATTRIBUTE' | translate }} + + + + {{ 'IDP.PREFERREDUSERNAMEATTRIBUTE' | translate }} + + + + {{ 'IDP.PROFILEATTRIBUTE' | translate }} + + +
diff --git a/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.scss b/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.scss index 31060727c2..7d02387d8e 100644 --- a/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.scss +++ b/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.scss @@ -4,3 +4,8 @@ max-width: 400px; padding-bottom: 1rem; } + +.attribute-more-row { + display: flex; + align-items: center; +} diff --git a/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.ts b/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.ts index 3ccf153de6..283a9940f0 100644 --- a/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.ts +++ b/console/src/app/modules/providers/ldap-attributes/ldap-attributes.component.ts @@ -29,6 +29,7 @@ export class LDAPAttributesComponent implements OnChanges, OnDestroy { profileAttribute: new FormControl('', []), }); + public showMore: boolean = false; constructor() { this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => { if (value) { diff --git a/console/src/app/modules/providers/provider-ldap/provider-ldap.component.html b/console/src/app/modules/providers/provider-ldap/provider-ldap.component.html index 75e2391b5c..21bec37703 100644 --- a/console/src/app/modules/providers/provider-ldap/provider-ldap.component.html +++ b/console/src/app/modules/providers/provider-ldap/provider-ldap.component.html @@ -17,12 +17,13 @@
{{ 'IDP.NAME' | translate }} - +

{{ 'IDP.LDAPCONNECTION' | translate }}

{{ 'IDP.BASEDN' | translate }} - +
{{ 'IDP.BINDDN' | translate }} - + {{ 'IDP.UPDATEBINDPASSWORD' | translate }} - + {{ 'IDP.BINDPASSWORD' | translate }}
@@ -62,16 +63,18 @@ {{ 'IDP.USERBASE' | translate }} - +

{{ 'IDP.LDAPATTRIBUTES' | translate }}

- - - - {{ - 'IDP.REQUIRED' | translate - }} -
-
-
+

{{ 'IDP.OPTIONAL' | translate }}

@@ -123,7 +115,7 @@ color="primary" mat-raised-button class="continue-button" - [disabled]="form.invalid || attributes.toObject().idAttribute === '' || form.disabled" + [disabled]="!form.valid || !attributes.toObject().idAttribute || form.disabled" type="submit" > {{ 'ACTIONS.SAVE' | translate }} diff --git a/console/src/app/modules/providers/provider-ldap/provider-ldap.component.ts b/console/src/app/modules/providers/provider-ldap/provider-ldap.component.ts index abf3938707..db54dbe6b5 100644 --- a/console/src/app/modules/providers/provider-ldap/provider-ldap.component.ts +++ b/console/src/app/modules/providers/provider-ldap/provider-ldap.component.ts @@ -20,7 +20,7 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/ 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 { minArrayLengthValidator, requiredValidator } from '../../form-field/validators/validators'; import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum'; @@ -30,7 +30,6 @@ import { PolicyComponentServiceType } from '../../policies/policy-component-type }) export class ProviderLDAPComponent { public updateBindPassword: boolean = false; - public showAttributes: boolean = false; public showOptional: boolean = false; public options: Options = new Options().setIsCreationAllowed(true).setIsLinkingAllowed(true); public attributes: LDAPAttributes = new LDAPAttributes(); @@ -54,15 +53,15 @@ export class ProviderLDAPComponent { ) { this.form = new FormGroup({ name: new FormControl('', [requiredValidator]), - serversList: new FormControl('', [requiredValidator]), + serversList: new FormControl([''], [minArrayLengthValidator(1)]), baseDn: new FormControl('', [requiredValidator]), bindDn: new FormControl('', [requiredValidator]), bindPassword: new FormControl('', [requiredValidator]), userBase: new FormControl('', [requiredValidator]), - userFiltersList: new FormControl('', [requiredValidator]), - userObjectClassesList: new FormControl('', [requiredValidator]), + userFiltersList: new FormControl([''], [minArrayLengthValidator(1)]), + userObjectClassesList: new FormControl([''], [minArrayLengthValidator(1)]), timeout: new FormControl(0), - startTls: new FormControl(false), + startTls: new FormControl(false), }); this.authService @@ -112,6 +111,7 @@ export class ProviderLDAPComponent { if (this.id) { this.getData(this.id); this.bindPassword?.setValidators([]); + this.bindPassword?.updateValueAndValidity(); } }); } @@ -125,12 +125,25 @@ export class ProviderLDAPComponent { this.service .getProviderByID(req) .then((resp) => { - this.provider = resp.idp; - this.loading = false; - if (this.provider?.config?.ldap) { - this.form.patchValue(this.provider.config.ldap); + if (resp.idp) { + this.provider = resp.idp; + this.loading = false; + this.name?.setValue(this.provider.name); - this.timeout?.setValue(this.provider.config.ldap.timeout?.seconds); + + const config = this.provider?.config?.ldap; + if (config) { + this.serversList?.setValue(config.serversList); + this.startTls?.setValue(config.startTls); + this.baseDn?.setValue(config.baseDn); + this.bindDn?.setValue(config.bindDn); + this.userBase?.setValue(config.userBase); + this.userObjectClassesList?.setValue(config.userObjectClassesList); + this.userFiltersList?.setValue(config.userFiltersList); + if (this.provider?.config?.ldap?.timeout?.seconds) { + this.timeout?.setValue(this.provider?.config?.ldap?.timeout?.seconds); + } + } } }) .catch((error) => { diff --git a/console/src/app/modules/providers/providers.scss b/console/src/app/modules/providers/providers.scss index 4241609431..4eb7702c6e 100644 --- a/console/src/app/modules/providers/providers.scss +++ b/console/src/app/modules/providers/providers.scss @@ -1,5 +1,8 @@ +@use '@angular/material' as mat; + @mixin identity-provider-theme($theme) { $is-dark-theme: map-get($theme, is-dark); + $background: map-get($theme, background); .identity-provider-desc { font-size: 14px; @@ -44,6 +47,14 @@ display: block; max-width: 400px; + &.pwd { + display: none; + } + + &.pwd.show { + display: block; + } + .name-hint { font-size: 12px; } @@ -63,6 +74,10 @@ } } + .string-list-component-wrapper { + max-width: 400px; + } + .identity-provider-content { display: flex; flex-direction: column; diff --git a/console/src/app/modules/string-list/string-list.component.html b/console/src/app/modules/string-list/string-list.component.html index 936bc9159f..1ff6a41e34 100644 --- a/console/src/app/modules/string-list/string-list.component.html +++ b/console/src/app/modules/string-list/string-list.component.html @@ -1,30 +1,43 @@ -
- - {{ title }} - - - -
+
+
+
+

{{ title }}*

+ +
+ +
+ + + -
-
- {{ str }} - - + +
+ + {{ + control.errors['errorsatleastone'].i18nKey | translate + }}
diff --git a/console/src/app/modules/string-list/string-list.component.scss b/console/src/app/modules/string-list/string-list.component.scss index 2d1779eb72..d44143914a 100644 --- a/console/src/app/modules/string-list/string-list.component.scss +++ b/console/src/app/modules/string-list/string-list.component.scss @@ -5,56 +5,50 @@ $background: map-get($theme, background); $is-dark-theme: map-get($theme, is-dark); $warn: map-get($theme, warn); - $warn-color: map-get($warn, 500); - $button-text-color: map-get($foreground, text); - $button-disabled-text-color: map-get($foreground, disabled-button); - $divider-color: map-get($foreground, dividers); - $secondary-text: map-get($foreground, secondary-text); + $warncolor: map-get($warn, 500); - .string-list { - width: 100%; + .form-array-list { + display: flex; + flex-direction: row; max-width: 400px; + background: if($is-dark-theme, #00000020, mat.get-color-from-palette($background, cards)); + margin-left: -1rem; + margin-right: -1rem; + padding: 0 1rem 0.5rem 1rem; + margin-top: 0.5rem; - .value-line { + .list-header-wrapper { display: flex; align-items: center; - margin: 0.5rem 0; - padding: 0 0 0 0.75rem; - border-radius: 4px; - background: map-get($background, infosection); + margin: 0.5rem -0.5rem 0 0; - .fill-space { - flex: 1; + .list-header { + font-size: 12px; } + } - .icon-button { - height: 30px; - line-height: 30px; + .form-field-list { + flex: 1; + display: flex; + flex-direction: column; - .icon { - font-size: 1rem; - margin-bottom: 3px; - } + .element-row { + display: flex; + align-items: center; - &:not(:hover) { - color: $secondary-text; + .formfield { + flex: 1; } } + + .control-error { + font-size: 12px; + color: $warncolor; + } + } + + .add-element-btn { + margin-bottom: 0rem; } } } - -.string-list-form { - display: flex; - align-items: flex-end; - min-width: 320px; - - .formfield { - width: 500px; - } - - button { - margin-bottom: 0.9rem; - margin-right: -0.5rem; - } -} diff --git a/console/src/app/modules/string-list/string-list.component.ts b/console/src/app/modules/string-list/string-list.component.ts index 3afa966aa1..c0380ad937 100644 --- a/console/src/app/modules/string-list/string-list.component.ts +++ b/console/src/app/modules/string-list/string-list.component.ts @@ -1,7 +1,7 @@ -import { Component, forwardRef, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Observable, Subject, takeUntil } from 'rxjs'; -import { requiredValidator } from '../form-field/validators/validators'; +import { Component, forwardRef, Input, OnDestroy, ViewChildren, ViewEncapsulation } from '@angular/core'; +import { ControlValueAccessor, FormArray, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { distinctUntilChanged, Subject, takeUntil } from 'rxjs'; +import { minArrayLengthValidator, requiredValidator } from '../form-field/validators/validators'; @Component({ selector: 'cnsl-string-list', @@ -16,22 +16,23 @@ import { requiredValidator } from '../form-field/validators/validators'; }, ], }) -export class StringListComponent implements ControlValueAccessor, OnInit, OnDestroy { +export class StringListComponent implements ControlValueAccessor, OnDestroy { @Input() title: string = ''; @Input() required: boolean = false; - @Input() public getValues: Observable = new Observable(); // adds formfieldinput to array on emission - @Input() public control: FormControl = new FormControl({ value: '', disabled: true }); + @Input() public control: FormControl = new FormControl({ value: [], disabled: true }); + private destroy$: Subject = new Subject(); - @ViewChild('redInput') input!: any; - private val: string[] = []; + @ViewChildren('stringInput') input!: any[]; + public val: string[] = []; - ngOnInit(): void { - this.getValues.pipe(takeUntil(this.destroy$)).subscribe(() => { - this.add(this.input.nativeElement); + public formArray: FormArray = new FormArray([new FormControl('', [requiredValidator])]); + + constructor() { + this.control.setValidators([minArrayLengthValidator(1)]); + this.formArray.valueChanges.pipe(takeUntil(this.destroy$), distinctUntilChanged()).subscribe((value) => { + this.value = value; }); - - this.required ? this.control.setValidators([requiredValidator]) : this.control.setValidators([]); } ngOnDestroy(): void { @@ -50,12 +51,24 @@ export class StringListComponent implements ControlValueAccessor, OnInit, OnDest } } + addArrayEntry() { + this.formArray.push(new FormControl('', [requiredValidator])); + } + + removeEntryAtIndex(index: number) { + this.formArray.removeAt(index); + } + + clearEntryAtIndex(index: number) { + this.formArray.controls[index].setValue(''); + } get value() { return this.val; } writeValue(value: string[]) { this.value = value; + value.map((v, i) => this.formArray.setControl(i, new FormControl(v, [requiredValidator]))); } registerOnChange(fn: any) { @@ -73,28 +86,4 @@ export class StringListComponent implements ControlValueAccessor, OnInit, OnDest this.control.enable(); } } - - public add(input: any): void { - if (this.control.valid) { - const trimmed = input.value.trim(); - if (trimmed) { - this.val ? this.val.push(input.value) : (this.val = [input.value]); - this.onChange(this.val); - this.onTouch(this.val); - } - if (input) { - input.value = ''; - } - } - } - - public remove(str: string): void { - const index = this.value.indexOf(str); - - if (index >= 0) { - this.value.splice(index, 1); - this.onChange(this.value); - this.onTouch(this.value); - } - } } diff --git a/console/src/app/modules/string-list/string-list.module.ts b/console/src/app/modules/string-list/string-list.module.ts index fe72b2adaa..db9322641b 100644 --- a/console/src/app/modules/string-list/string-list.module.ts +++ b/console/src/app/modules/string-list/string-list.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatIconModule } from '@angular/material/icon'; import { MatLegacyButtonModule } from '@angular/material/legacy-button'; +import { MatLegacyChipsModule } from '@angular/material/legacy-chips'; import { MatLegacyTooltipModule } from '@angular/material/legacy-tooltip'; import { TranslateModule } from '@ngx-translate/core'; import { InputModule } from '../input/input.module'; @@ -15,6 +16,7 @@ import { StringListComponent } from './string-list.component'; InputModule, FormsModule, ReactiveFormsModule, + MatLegacyChipsModule, TranslateModule, MatIconModule, MatLegacyTooltipModule, diff --git a/console/src/app/pages/users/user-create-machine/user-create-machine.component.html b/console/src/app/pages/users/user-create-machine/user-create-machine.component.html index 9685f90665..2e273a88d6 100644 --- a/console/src/app/pages/users/user-create-machine/user-create-machine.component.html +++ b/console/src/app/pages/users/user-create-machine/user-create-machine.component.html @@ -10,11 +10,11 @@
- {{ 'USER.MACHINE.USERNAME' | translate }}* + {{ 'USER.MACHINE.USERNAME' | translate }} - {{ 'USER.MACHINE.NAME' | translate }}* + {{ 'USER.MACHINE.NAME' | translate }} diff --git a/console/src/app/pages/users/user-create/user-create.component.html b/console/src/app/pages/users/user-create/user-create.component.html index acd3a8e103..e74020ea9e 100644 --- a/console/src/app/pages/users/user-create/user-create.component.html +++ b/console/src/app/pages/users/user-create/user-create.component.html @@ -13,11 +13,11 @@
- {{ 'USER.PROFILE.EMAIL' | translate }}* + {{ 'USER.PROFILE.EMAIL' | translate }} - {{ 'USER.PROFILE.USERNAME' | translate }}* + {{ 'USER.PROFILE.USERNAME' | translate }} - {{ 'USER.PROFILE.FIRSTNAME' | translate }}* + {{ 'USER.PROFILE.FIRSTNAME' | translate }} - {{ 'USER.PROFILE.LASTNAME' | translate }}* + {{ 'USER.PROFILE.LASTNAME' | translate }} diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index d54974b5b2..eabe26ba69 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -247,6 +247,7 @@ }, "ERRORS": { "REQUIRED": "Bitte fülle dieses Feld aus.", + "ATLEASTONE": "Geben Sie mindestens einen Wert an.", "TOKENINVALID": { "TITLE": "Du bist abgemeldet", "DESCRIPTION": "Klicke auf \"Einloggen\", um Dich erneut anzumelden." diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 8aabe4d58e..d85876e19f 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -248,6 +248,7 @@ }, "ERRORS": { "REQUIRED": "Please fill in this field.", + "ATLEASTONE": "Provide at least one value.", "TOKENINVALID": { "TITLE": "Your authorization token has expired.", "DESCRIPTION": "Click the button below to log in again." diff --git a/console/src/assets/i18n/es.json b/console/src/assets/i18n/es.json index c9c1a26829..ac8799d411 100644 --- a/console/src/assets/i18n/es.json +++ b/console/src/assets/i18n/es.json @@ -248,6 +248,7 @@ }, "ERRORS": { "REQUIRED": "Por favor rellena este campo.", + "ATLEASTONE": "Proporcione al menos un valor.", "TOKENINVALID": { "TITLE": "Tu token de autorización token ha caducado.", "DESCRIPTION": "Haz clic en el botón más abajo para iniciar sesión otra vez." diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json index 6c11c83522..adb8b36f22 100644 --- a/console/src/assets/i18n/fr.json +++ b/console/src/assets/i18n/fr.json @@ -247,6 +247,7 @@ }, "ERRORS": { "REQUIRED": "Remplis ce champ s'il te plaît.", + "ATLEASTONE": "Indiquez au moins une valeur.", "TOKENINVALID": { "TITLE": "Votre jeton d'autorisation a expiré.", "DESCRIPTION": "Cliquez sur le bouton ci-dessous pour vous reconnecter." diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index 4b9c88bae4..9022045573 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -247,6 +247,7 @@ }, "ERRORS": { "REQUIRED": "Compilare questo campo.", + "ATLEASTONE": "Inserisci almeno un valore.", "TOKENINVALID": { "TITLE": "Il tuo Access Token \u00e8 scaduto.", "DESCRIPTION": "Clicca il pulsante per richiedere una nuova sessione." diff --git a/console/src/assets/i18n/ja.json b/console/src/assets/i18n/ja.json index 5127adf698..de94a152bc 100644 --- a/console/src/assets/i18n/ja.json +++ b/console/src/assets/i18n/ja.json @@ -248,6 +248,7 @@ }, "ERRORS": { "REQUIRED": "一部の必須項目が不足しています。", + "ATLEASTONE": "少なくとも 1 つの値を指定してください。", "TOKENINVALID": { "TITLE": "トークンが期限切れになりました。", "DESCRIPTION": "下のボタンをクリックして、もう一度ログインする。" diff --git a/console/src/assets/i18n/pl.json b/console/src/assets/i18n/pl.json index 594e3654b2..74c5d81531 100644 --- a/console/src/assets/i18n/pl.json +++ b/console/src/assets/i18n/pl.json @@ -247,6 +247,7 @@ }, "ERRORS": { "REQUIRED": "Proszę wypełnić to pole.", + "ATLEASTONE": "Podaj co najmniej jedną wartość.", "TOKENINVALID": { "TITLE": "Twój token autoryzacji wygasł.", "DESCRIPTION": "Kliknij przycisk poniżej, aby ponownie się zalogować." diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json index 0c0b953e38..b560132685 100644 --- a/console/src/assets/i18n/zh.json +++ b/console/src/assets/i18n/zh.json @@ -247,6 +247,7 @@ }, "ERRORS": { "REQUIRED": "请填写此栏", + "ATLEASTONE": "P至少提供一个值。", "TOKENINVALID": { "TITLE": "您的授权令牌已过期。", "DESCRIPTION": "点击下方按钮再次登录。"