feat(console): set email verified on org creation, disable svg upload, password page optimizations (#4149)

* feat: set email verified on org creation

* catch svg files and throw error

* password changes

* passwordpage

* rm log

* it

* fr

* localhost env

* Update fr.json

Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com>
Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Max Peintner
2022-08-26 09:34:44 +02:00
committed by GitHub
parent e39d82c031
commit cbb5e90bac
17 changed files with 201 additions and 127 deletions

View File

@@ -17,6 +17,15 @@ const routes: Routes = [
path: 'signedout',
loadChildren: () => import('./pages/signedout/signedout.module').then((m) => m.SignedoutModule),
},
{
path: 'orgs/create',
component: OrgCreateComponent,
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['(org.create)?(iam.write)?'],
},
loadChildren: () => import('./pages/org-create/org-create.module').then((m) => m.OrgCreateModule),
},
{
path: 'orgs',
loadChildren: () => import('./pages/org-list/org-list.module').then((m) => m.OrgListModule),
@@ -52,15 +61,6 @@ const routes: Routes = [
roles: ['iam.read', 'iam.write'],
},
},
{
path: 'org/create',
component: OrgCreateComponent,
canActivate: [AuthGuard, RoleGuard],
data: {
roles: ['(org.create)?(iam.write)?'],
},
loadChildren: () => import('./pages/org-create/org-create.module').then((m) => m.OrgCreateModule),
},
{
path: 'org',
loadChildren: () => import('./pages/orgs/org.module').then((m) => m.OrgModule),

View File

@@ -28,7 +28,7 @@
<a
class="nav-item"
[routerLinkActiveOptions]="{ exact: true }"
[routerLinkActiveOptions]="{ exact: false }"
[routerLinkActive]="['active']"
[routerLink]="['/orgs']"
>

View File

@@ -56,7 +56,7 @@
</ng-template>
<ng-template cnslHasRole [hasRole]="['org.create', 'iam.write']">
<button mat-button [routerLink]="['/org/create']" (click)="closedCard.emit()">
<button mat-button [routerLink]="['/orgs/create']" (click)="closedCard.emit()">
<mat-icon class="avatar">add</mat-icon>
{{ 'MENU.NEWORG' | translate }}
</button>

View File

@@ -8,10 +8,10 @@
</cnsl-filter-org>
<ng-template actions cnslHasRole [hasRole]="['org.create', 'iam.write']">
<a [routerLink]="['/org', 'create']" color="primary" mat-raised-button class="cnsl-action-button">
<a [routerLink]="['/orgs', 'create']" color="primary" mat-raised-button class="cnsl-action-button">
<mat-icon class="icon">add</mat-icon>
<span>{{ 'ACTIONS.NEW' | translate }}</span>
<cnsl-action-keys (actionTriggered)="gotoRouterLink(['/org', 'create'])"> </cnsl-action-keys>
<cnsl-action-keys (actionTriggered)="gotoRouterLink(['/orgs', 'create'])"> </cnsl-action-keys>
</a>
</ng-template>

View File

@@ -4,15 +4,15 @@ import { MatDialog } from '@angular/material/dialog';
import { Subject, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import {
GetLabelPolicyResponse as AdminGetLabelPolicyResponse,
GetPreviewLabelPolicyResponse as AdminGetPreviewLabelPolicyResponse,
UpdateLabelPolicyRequest,
GetLabelPolicyResponse as AdminGetLabelPolicyResponse,
GetPreviewLabelPolicyResponse as AdminGetPreviewLabelPolicyResponse,
UpdateLabelPolicyRequest,
} from 'src/app/proto/generated/zitadel/admin_pb';
import {
AddCustomLabelPolicyRequest,
GetLabelPolicyResponse as MgmtGetLabelPolicyResponse,
GetPreviewLabelPolicyResponse as MgmtGetPreviewLabelPolicyResponse,
UpdateCustomLabelPolicyRequest,
AddCustomLabelPolicyRequest,
GetLabelPolicyResponse as MgmtGetLabelPolicyResponse,
GetPreviewLabelPolicyResponse as MgmtGetPreviewLabelPolicyResponse,
UpdateCustomLabelPolicyRequest,
} from 'src/app/proto/generated/zitadel/management_pb';
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { LabelPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
@@ -112,7 +112,9 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
const file = filelist.item(0);
if (file) {
if (file.size > MAX_ALLOWED_SIZE) {
this.toast.showInfo('POLICY.PRIVATELABELING.MAXSIZEEXCEEDED', true);
this.toast.showError('POLICY.PRIVATELABELING.MAXSIZEEXCEEDED', false, true);
} else if (file.type === 'image/svg+xml') {
this.toast.showError('POLICY.PRIVATELABELING.NOSVGSUPPORTED', false, true);
} else {
const formData = new FormData();
formData.append('file', file);

View File

@@ -115,14 +115,23 @@
</mat-select>
</cnsl-form-field>
<mat-checkbox
class="checkbox"
[(ngModel)]="usePassword"
[ngModelOptions]="{ standalone: true }"
(change)="initPwdValidators()"
>
{{ 'ORG.PAGES.USEPASSWORD' | translate }}</mat-checkbox
>
<div class="email-is-verified">
<mat-checkbox class="block-checkbox" formControlName="isVerified">
{{ 'USER.LOGINMETHODS.EMAIL.ISVERIFIED' | translate }}
</mat-checkbox>
<mat-checkbox
class="block-checkbox"
[(ngModel)]="usePassword"
[ngModelOptions]="{ standalone: true }"
(change)="initPwdValidators()"
>
{{ 'ORG.PAGES.USEPASSWORD' | translate }}</mat-checkbox
>
<cnsl-info-section class="full-width desc">
<span>{{ 'USER.CREATE.INITMAILDESCRIPTION' | translate }}</span>
</cnsl-info-section>
</div>
<ng-container *ngIf="usePassword && pwdForm">
<p class="section cnsl-secondary-text">{{ 'USER.CREATE.PASSWORDSECTION' | translate }}</p>

View File

@@ -58,6 +58,16 @@ h1 {
flex: 1 0 33%;
margin: 0 0.5rem;
}
.email-is-verified {
flex-basis: 100%;
margin: 1.5rem 0.5rem 0 0.5rem;
.block-checkbox {
display: block;
margin: 0.25rem 0;
}
}
}
.pwd-form {
@@ -109,11 +119,6 @@ h1 {
}
}
.checkbox {
flex-basis: 100%;
margin: 0.5rem;
}
.complexity-view {
width: 100%;
margin: 0 0.5rem;

View File

@@ -10,6 +10,7 @@ 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';
import { AdminService } from 'src/app/services/admin.service';
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';
@@ -69,7 +70,16 @@ export class OrgCreateComponent {
private fb: UntypedFormBuilder,
private mgmtService: ManagementService,
private authService: GrpcAuthService,
private breadcrumbService: BreadcrumbService,
) {
const instanceBread = new Breadcrumb({
type: BreadcrumbType.INSTANCE,
name: 'Instance',
routerLink: ['/instance'],
});
breadcrumbService.setBreadcrumb([instanceBread]);
this.authService
.isAllowed(['iam.write'])
.pipe(take(1))
@@ -96,7 +106,9 @@ export class OrgCreateComponent {
createOrgRequest.setDomain(this.domain?.value);
const humanRequest: SetUpOrgRequest.Human = new SetUpOrgRequest.Human();
humanRequest.setEmail(new SetUpOrgRequest.Human.Email().setEmail(this.email?.value));
humanRequest.setEmail(
new SetUpOrgRequest.Human.Email().setEmail(this.email?.value).setIsEmailVerified(this.isVerified?.value),
);
humanRequest.setUserName(this.userName?.value);
const profile: SetUpOrgRequest.Human.Profile = new SetUpOrgRequest.Human.Profile();
@@ -143,6 +155,7 @@ export class OrgCreateComponent {
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
email: ['', [Validators.required]],
isVerified: [false, []],
gender: [''],
nickName: [''],
preferredLanguage: [''],
@@ -243,6 +256,10 @@ export class OrgCreateComponent {
return this.userForm.get('email');
}
public get isVerified(): AbstractControl | null {
return this.userForm.get('isVerified');
}
public get nickName(): AbstractControl | null {
return this.userForm.get('nickName');
}

View File

@@ -9,6 +9,7 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { CreateLayoutModule } from 'src/app/modules/create-layout/create-layout.module';
import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
import { InputModule } from 'src/app/modules/input/input.module';
import { PasswordComplexityViewModule } from 'src/app/modules/password-complexity-view/password-complexity-view.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
@@ -23,6 +24,7 @@ import { OrgCreateComponent } from './org-create.component';
CommonModule,
FormsModule,
ReactiveFormsModule,
InfoSectionModule,
InputModule,
MatButtonModule,
MatIconModule,

View File

@@ -1,41 +1,45 @@
<cnsl-detail-layout [hasBackButton]="true" title="{{ 'USER.PASSWORD.TITLE' | translate }}"
description="{{ 'USER.PASSWORD.DESCRIPTION' | translate }}">
<cnsl-detail-layout [hasBackButton]="true" title="{{ 'USER.PASSWORD.TITLE' | translate }}">
<p class="password-info cnsl-secondary-text" sub>{{ 'USER.PASSWORD.DESCRIPTION' | translate }}</p>
<ng-container *ngIf="userId; else authUser">
<div class="validation" *ngIf="this.policy">
<cnsl-password-complexity-view [policy]="this.policy" [password]="password">
</cnsl-password-complexity-view>
</div>
<form
*ngIf="passwordForm"
autocomplete="new-password"
[formGroup]="passwordForm"
(ngSubmit)="setInitialPassword(userId)"
>
<div class="password-content">
<div class="side-by-side">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PASSWORD.NEW' | translate }}</cnsl-label>
<input cnslInput autocomplete="off" name="password" formControlName="password" type="password" />
<form *ngIf="passwordForm" autocomplete="new-password" [formGroup]="passwordForm"
(ngSubmit)="setInitialPassword(userId)">
<div class="content center">
<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>
<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>
<div class="btn-container">
<button class="submit-button" [disabled]="passwordForm.invalid" mat-raised-button color="primary">{{
'USER.PASSWORD.SET' | translate }}</button>
<div class="validation" *ngIf="this.policy">
<cnsl-password-complexity-view [policy]="this.policy" [password]="password"> </cnsl-password-complexity-view>
</div>
</div>
<button class="submit-button" [disabled]="passwordForm.invalid" mat-raised-button color="primary">
{{ 'USER.PASSWORD.SET' | translate }}
</button>
</form>
</ng-container>
<ng-template #authUser>
<form *ngIf="passwordForm" [formGroup]="passwordForm" (ngSubmit)="setPassword()">
<div class="content">
<div class="password-content">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PASSWORD.OLD' | translate }}</cnsl-label>
<input cnslInput autocomplete="off" name="password" type="password" formControlName="currentPassword" />
@@ -45,29 +49,36 @@
</cnsl-form-field>
<div class="validation between" *ngIf="this.policy">
<cnsl-password-complexity-view [policy]="this.policy" [password]="newPassword">
</cnsl-password-complexity-view>
<cnsl-password-complexity-view [policy]="this.policy" [password]="newPassword"> </cnsl-password-complexity-view>
</div>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PASSWORD.NEW' | translate }}</cnsl-label>
<input cnslInput autocomplete="off" name="new password" type="password" formControlName="newPassword" />
<div class="side-by-side">
<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>
<input cnslInput autocomplete="off" name="password repeating" type="password"
formControlName="confirmPassword" />
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
</span>
</cnsl-form-field>
<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>
<input
cnslInput
autocomplete="off"
name="password repeating"
type="password"
formControlName="confirmPassword"
/>
<span cnslError *ngIf="confirmPassword?.errors?.notequal">
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
</span>
</cnsl-form-field>
</div>
</div>
<button class="submit-button" [disabled]="passwordForm.invalid" mat-raised-button color="primary">{{
'USER.PASSWORD.RESET' | translate }}</button>
<button class="submit-button" [disabled]="passwordForm.invalid" mat-raised-button color="primary">
{{ 'USER.PASSWORD.RESET' | translate }}
</button>
</form>
</ng-template>
</cnsl-detail-layout>
</cnsl-detail-layout>

View File

@@ -1,17 +1,34 @@
.content {
.password-info {
margin: -1rem 0 0 0;
font-size: 14px;
}
.password-content {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 -0.5rem;
max-width: 40rem;
.formfield {
margin: 0 0.5rem;
.side-by-side {
display: flex;
flex-wrap: wrap;
flex-direction: row;
margin: 0 -0.5rem;
width: 100%;
max-width: 400px;
@media only screen and (max-width: 500px) {
flex-direction: column;
}
.formfield {
flex: 1;
margin: 0 0.5rem;
}
}
&.center {
align-items: center;
.formfield {
max-width: 400px;
width: 100%;
}
}
@@ -22,7 +39,7 @@
}
.submit-button {
margin-top: 100px;
margin-top: 2rem;
display: block;
padding: 0.5rem 4rem;
}

View File

@@ -33,7 +33,7 @@ export class ToastService {
}
}
public showError(error: any | string, isGrpc: boolean = true): void {
public showError(error: any | string, isGrpc: boolean = true, i18nKey: boolean = false): void {
if (isGrpc) {
const { message, code, metadata } = error;
if (code !== 16) {
@@ -44,6 +44,13 @@ export class ToastService {
this.showMessage(decodeURI(message), value, false);
});
}
} else if (i18nKey) {
this.translate
.get(error)
.pipe(take(1))
.subscribe((value) => {
this.showMessage(value, '', false);
});
} else {
this.showMessage(error as string, '', false);
}

View File

@@ -482,7 +482,7 @@
"SET": "Passwort neu setzen",
"RESENDNOTIFICATION": "Email zum Zurücksetzen senden",
"REQUIRED": "Bitte prüfe, dass alle notwendigen Felder ausgefüllt sind.",
"MINLENGTHERROR": "Das Passwort muss mindestens {{value}} Zeichen lang sein.",
"MINLENGTHERROR": "Muss mindestens {{value}} Zeichen lang sein.",
"NOTEQUAL": "Die Passwörter stimmen nicht überein."
},
"ID": "ID",
@@ -542,10 +542,10 @@
"REQUIRED": "Das Eingabefeld ist leer.",
"MINLENGTH": "Das Passwort muss mindestens {{requiredLength}} Zeichen lang sein.",
"NOEMAIL": "Benutzername darf keine E-Mail-Adresse sein.",
"UPPERCASEMISSING": "Passwort muss einen Grossbuchstaben beinhalten.",
"LOWERCASEMISSING": "Passwort muss einen Kleinbuchstaben beinhalten.",
"SYMBOLERROR": "Das Passwort muss ein Symbol/Satzzeichen beinhalten.",
"NUMBERERROR": "Das Passwort muss eine Ziffer beinhalten."
"UPPERCASEMISSING": "Muss einen Grossbuchstaben beinhalten.",
"LOWERCASEMISSING": "Muss einen Kleinbuchstaben beinhalten.",
"SYMBOLERROR": "Muss ein Symbol/Satzzeichen beinhalten.",
"NUMBERERROR": "Muss eine Ziffer beinhalten."
},
"STATE": {
"0": "Unbekannt",
@@ -978,9 +978,9 @@
"PWD_COMPLEXITY": {
"TITLE": "Passwortkomplexität",
"DESCRIPTION": "Stellt sicher, dass alle festgelegten Passwörter einem bestimmten Muster entsprechen.",
"SYMBOLANDNUMBERERROR": "Das Passwort muss ein Symbol/Satzzeichen und eine Ziffer beinhalten.",
"SYMBOLERROR": "Das Passwort muss ein Symbol/Satzzeichen beinhalten.",
"NUMBERERROR": "Das Passwort muss eine Ziffer beinhalten.",
"SYMBOLANDNUMBERERROR": "Muss ein Symbol/Satzzeichen und eine Ziffer beinhalten.",
"SYMBOLERROR": "Muss ein Symbol/Satzzeichen beinhalten.",
"NUMBERERROR": "Muss eine Ziffer beinhalten.",
"PATTERNERROR": "Das Passwort erfüllt nicht die vorgeschriebene Richtlinie."
},
"PRIVATELABELING": {
@@ -1005,6 +1005,7 @@
"MAXSIZE": "Die maximale Grösse von Uploads ist mit 524kB begrenzt",
"EMAILNOSVG": "Das SVG Dateiformat wird nicht in emails unterstützt. Laden Sie deshalb ihr Logo im PNG oder einem anderen unterstützten Format hoch.",
"MAXSIZEEXCEEDED": "Maximale Grösse von 524kB überschritten",
"NOSVGSUPPORTED": "SVG werden nicht unterstützt!",
"FONTINLOGINONLY": "Die Schriftart wird momentan nur im Login interface angezeigt.",
"VIEWS": {
"PREVIEW": "Vorschau",

View File

@@ -482,7 +482,7 @@
"SET": "Set New Password",
"RESENDNOTIFICATION": "Send Password Reset Link",
"REQUIRED": "Some required fields are missing.",
"MINLENGTHERROR": "The password has to be at least {{value}} characters long.",
"MINLENGTHERROR": "Has to be at least {{value}} characters long.",
"NOTEQUAL": "The passwords provided do not match."
},
"ID": "ID",
@@ -542,10 +542,10 @@
"REQUIRED": "The input field is empty.",
"MINLENGTH": "The password has to be at least {{requiredLength}} characters long.",
"NOEMAIL": "The user name cannot be an e-mail address.",
"UPPERCASEMISSING": "The password must include an uppercase character.",
"LOWERCASEMISSING": "The password must include a lowercase character.",
"SYMBOLERROR": "The password must include a symbol or punctuation mark.",
"NUMBERERROR": "The password must include a digit."
"UPPERCASEMISSING": "Must include an uppercase character.",
"LOWERCASEMISSING": "Must include a lowercase character.",
"SYMBOLERROR": "Must include a symbol or punctuation mark.",
"NUMBERERROR": "Must include a digit."
},
"STATE": {
"0": "Unknown",
@@ -978,9 +978,9 @@
"PWD_COMPLEXITY": {
"TITLE": "Password Complexity",
"DESCRIPTION": "Ensures that all set passwords correspond to a specific pattern",
"SYMBOLANDNUMBERERROR": "The password must consist of a digit and a symbol/punctuation mark.",
"SYMBOLERROR": "The password must include a symbol/punctuation mark.",
"NUMBERERROR": "The password must include a digit.",
"SYMBOLANDNUMBERERROR": "Must consist of a digit and a symbol/punctuation mark.",
"SYMBOLERROR": "Must include a symbol/punctuation mark.",
"NUMBERERROR": "Must include a digit.",
"PATTERNERROR": "The password does not meet the required pattern."
},
"PRIVATELABELING": {
@@ -1005,6 +1005,7 @@
"MAXSIZE": "The maximum size is limited to 524kB",
"EMAILNOSVG": "The SVG file format is not supported in emails. Therefore upload your logo in PNG or other supported format.",
"MAXSIZEEXCEEDED": "Maximum size of 524kB exceeded.",
"NOSVGSUPPORTED": "SVG are not supported!",
"FONTINLOGINONLY": "The font is currently only displayed in the login interface.",
"VIEWS": {
"PREVIEW": "Preview",

View File

@@ -482,7 +482,7 @@
"SET": "Définir un nouveau mot de passe",
"RESENDNOTIFICATION": "Envoyer le lien de réinitialisation du mot de passe",
"REQUIRED": "Certains champs obligatoires sont manquants.",
"MINLENGTHERROR": "Le mot de passe doit comporter au moins{{value}} caractères.",
"MINLENGTHERROR": "Doit comporter au moins {{value}} caractères.",
"NOTEQUAL": "Les mots de passe fournis ne correspondent pas."
},
"ID": "ID",
@@ -542,10 +542,10 @@
"REQUIRED": "Le champ de saisie est vide.",
"MINLENGTH": "Le mot de passe doit comporter au moins{{length}} caractères.",
"NOEMAIL": "Le nom d'utilisateur ne peut pas être une adresse électronique.",
"UPPERCASEMISSING": "Le mot de passe doit comporter un caractère majuscule.",
"LOWERCASEMISSING": "Le mot de passe doit inclure un caractère minuscule.",
"SYMBOLERROR": "Le mot de passe doit inclure un symbole ou un signe de ponctuation.",
"NUMBERERROR": "Le mot de passe doit contenir un chiffre."
"UPPERCASEMISSING": "Doit inclure un caractère majuscule.",
"LOWERCASEMISSING": "Doit inclure un caractère minuscule.",
"SYMBOLERROR": "Doit inclure un symbole ou un signe de ponctuation.",
"NUMBERERROR": "Doit inclure un chiffre."
},
"STATE": {
"0": "Inconnu",
@@ -978,9 +978,9 @@
"PWD_COMPLEXITY": {
"TITLE": "Complexité des mots de passe",
"DESCRIPTION": "Assure que tous les mots de passe définis correspondent à un modèle spécifique.",
"SYMBOLANDNUMBERERROR": "Le mot de passe doit être composé d'un chiffre et d'un symbole/une marque de ponctuation.",
"SYMBOLERROR": "Le mot de passe doit comprendre un symbole ou un signe de ponctuation.",
"NUMBERERROR": "Le mot de passe doit comprendre un chiffre.",
"SYMBOLANDNUMBERERROR": "Doit être composé d'un chiffre et d'un symbole/signe de ponctuation.",
"SYMBOLERROR": "Doit inclure un symbole/un signe de ponctuation.",
"NUMBERERROR": "Doit inclure un chiffre.",
"PATTERNERROR": "Le mot de passe ne correspond pas au modèle requis."
},
"PRIVATELABELING": {
@@ -1005,6 +1005,7 @@
"MAXSIZE": "La taille maximale est limitée à 524 Ko.",
"EMAILNOSVG": "Le format de fichier SVG n'est pas supporté dans les emails. Téléchargez donc votre logo en PNG ou dans un autre format pris en charge.",
"MAXSIZEEXCEEDED": "La taille maximale de 524kB est dépassée.",
"NOSVGSUPPORTED": "SVG n'est pas pris en charge",
"FONTINLOGINONLY": "La police n'est actuellement affichée que dans l'interface de connexion.",
"VIEWS": {
"PREVIEW": "Aperçu",

View File

@@ -482,7 +482,7 @@
"SET": "Imposta nuova password",
"RESENDNOTIFICATION": "Invia email per la reimpostazione",
"REQUIRED": "Mancano alcuni campi obbligatori.",
"MINLENGTHERROR": "La password deve essere lunga almeno {{valore}} caratteri.",
"MINLENGTHERROR": "Deve essere lunga almeno {{valore}} caratteri.",
"NOTEQUAL": "Le password fornite non corrispondono."
},
"ID": "ID",
@@ -540,12 +540,12 @@
"INVALIDPATTERN": "La password non soddisfa le regole definite.",
"NOTANEMAIL": "Il valore dato non \u00e8 un indirizzo e-mail",
"REQUIRED": "Il campo di input \u00e8 vuoto.",
"MINLENGTH": "La password deve essere lunga almeno {{requiredLength}} caratteri.",
"MINLENGTH": "Deve essere lunga almeno {{requiredLength}} caratteri.",
"NOEMAIL": "Il nome utente non pu\u00f2 essere un indirizzo e-mail.",
"UPPERCASEMISSING": "La password deve includere un carattere maiuscolo.",
"LOWERCASEMISSING": "La password deve includere un carattere minuscolo.",
"SYMBOLERROR": "La password deve includere un simbolo o un segno di punteggiatura.",
"NUMBERERROR": "La password deve includere una cifra."
"UPPERCASEMISSING": "Deve includere un carattere maiuscolo.",
"LOWERCASEMISSING": "Deve includere un carattere minuscolo.",
"SYMBOLERROR": "Deve includere un simbolo o un segno di punteggiatura.",
"NUMBERERROR": "Deve includere una cifra."
},
"STATE": {
"0": "Sconosciuto",
@@ -978,9 +978,9 @@
"PWD_COMPLEXITY": {
"TITLE": "Complessit\u00e0 della password",
"DESCRIPTION": "Assicura che tutte le password impostate corrispondano a un modello specifico",
"SYMBOLANDNUMBERERROR": "La password deve essere composta da una cifra e un simbolo/segno di interpunzione.",
"SYMBOLERROR": "La password deve includere un simbolo/segno di punteggiatura.",
"NUMBERERROR": "La password deve includere una cifra.",
"SYMBOLANDNUMBERERROR": "Deve essere composta da una cifra e un simbolo/segno di interpunzione.",
"SYMBOLERROR": "Deve includere un simbolo/segno di punteggiatura.",
"NUMBERERROR": "Deve includere una cifra.",
"PATTERNERROR": "La password non corrisponde al modello richiesto."
},
"PRIVATELABELING": {
@@ -1005,6 +1005,7 @@
"MAXSIZE": "La dimensione massima \u00e8 limitata a 524kB",
"EMAILNOSVG": "Il formato di file SVG non \u00e8 supportato nelle email. Perci\u00f2 carica il tuo logo in PNG o in un altro formato supportato.",
"MAXSIZEEXCEEDED": "Dimensione massima di 524kB superata.",
"NOSVGSUPPORTED": "SVG non sono supportati",
"FONTINLOGINONLY": "Il carattere \u00e8 attualmente visualizzato solo nell'interfaccia di accesso.",
"VIEWS": {
"PREVIEW": "Anteprima",