[ACS-6085] user is not prevented from renaming library to name containing only spaces (#3476)

* ACS-6085 Prevent user from renaming library to name containing only spaces

* ACS-6085 Trimmed value

* ACS-6085 Unit tests for titleErrorTranslationKey and update function

* ACS-6085 Unit tests

* ACS-6085 Removed redundant code

* ACS-6085 Set type for validateEmptyName function

* ACS-6085 Rename error translation key for required error

* ACS-6085 Empty commit
This commit is contained in:
AleksanderSklorz
2023-10-16 23:29:19 +02:00
committed by GitHub
parent 928c6b5731
commit 686e6c9dbb
4 changed files with 92 additions and 7 deletions

View File

@@ -92,7 +92,7 @@
/>
<mat-hint *ngIf="libraryTitleExists">{{ 'LIBRARY.HINTS.SITE_TITLE_EXISTS' | translate }}</mat-hint>
<mat-error>
{{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }}
{{ titleErrorTranslationKey | translate }}
</mat-error>
</mat-form-field>

View File

@@ -167,6 +167,21 @@ describe('LibraryMetadataFormComponent', () => {
expect(store.dispatch).toHaveBeenCalledWith(new UpdateLibraryAction(siteEntryModel));
});
it('should update library node with trimmed title', () => {
component.node.entry.role = Site.RoleEnum.SiteManager;
siteEntryModel.title = ' some title ';
component.node.entry.title = siteEntryModel.title;
component.ngOnInit();
component.update();
expect(store.dispatch).toHaveBeenCalledWith(
new UpdateLibraryAction({
...siteEntryModel,
title: siteEntryModel.title.trim()
})
);
});
it('should call markAsPristine on form when updating valid form and has permission to update', () => {
component.node.entry.role = Site.RoleEnum.SiteManager;
spyOn(component.form, 'markAsPristine');
@@ -264,6 +279,23 @@ describe('LibraryMetadataFormComponent', () => {
expect(component.libraryTitleExists).toBe(true);
}));
it('should call findSites on queriesApi with trimmed title', fakeAsync(() => {
const title = ' test ';
spyOn(component.queriesApi, 'findSites').and.returnValue(
Promise.resolve({
list: { entries: [{ entry: { title } }] }
} as SitePaging)
);
component.ngOnInit();
component.form.controls.title.setValue(title);
tick(300);
expect(component.queriesApi.findSites).toHaveBeenCalledWith(title.trim(), {
maxItems: 1,
fields: ['title']
});
}));
it('should not warn if library name input is the same with library node data', fakeAsync(() => {
spyOn(component['queriesApi'], 'findSites').and.returnValue(
Promise.resolve({
@@ -293,4 +325,25 @@ describe('LibraryMetadataFormComponent', () => {
tick(500);
expect(component.libraryTitleExists).toBe(false);
}));
it('should set proper titleErrorTranslationKey when there is error for empty title', () => {
component.ngOnInit();
component.form.controls.title.setValue(' ');
expect(component.titleErrorTranslationKey).toBe('LIBRARY.ERRORS.ONLY_SPACES');
});
it('should set proper titleErrorTranslationKey when there is error for too long title', () => {
component.ngOnInit();
component.form.controls.title.setValue('t'.repeat(257));
expect(component.titleErrorTranslationKey).toBe('LIBRARY.ERRORS.TITLE_TOO_LONG_OR_MISSING');
});
it('should set proper titleErrorTranslationKey when there is error for missing title', () => {
component.ngOnInit();
component.form.controls.title.setValue('');
expect(component.titleErrorTranslationKey).toBe('LIBRARY.ERRORS.TITLE_TOO_LONG_OR_MISSING');
});
});

View File

@@ -23,7 +23,17 @@
*/
import { Component, Input, OnChanges, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { UntypedFormGroup, UntypedFormControl, Validators, FormGroupDirective, NgForm, FormsModule, ReactiveFormsModule } from '@angular/forms';
import {
UntypedFormGroup,
UntypedFormControl,
Validators,
FormGroupDirective,
NgForm,
FormsModule,
ReactiveFormsModule,
FormControl,
ValidationErrors
} from '@angular/forms';
import { QueriesApi, SiteEntry, SitePaging } from '@alfresco/js-api';
import { Store } from '@ngrx/store';
import {
@@ -77,11 +87,17 @@ export class InstantErrorStateMatcher implements ErrorStateMatcher {
})
export class LibraryMetadataFormComponent implements OnInit, OnChanges, OnDestroy {
private _queriesApi: QueriesApi;
private _titleErrorTranslationKey: string;
get queriesApi(): QueriesApi {
this._queriesApi = this._queriesApi ?? new QueriesApi(this.alfrescoApiService.getInstance());
return this._queriesApi;
}
get titleErrorTranslationKey(): string {
return this._titleErrorTranslationKey;
}
@Input()
node: SiteEntry;
@@ -96,7 +112,7 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges, OnDestro
form: UntypedFormGroup = new UntypedFormGroup({
id: new UntypedFormControl({ value: '', disabled: true }),
title: new UntypedFormControl({ value: '' }, [Validators.required, Validators.maxLength(256)]),
title: new UntypedFormControl({ value: '' }, [Validators.required, Validators.maxLength(256), this.validateEmptyName]),
description: new UntypedFormControl({ value: '' }, [Validators.maxLength(512)]),
visibility: new UntypedFormControl(this.libraryType[0].value)
});
@@ -124,7 +140,14 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges, OnDestro
ngOnInit() {
this.updateForm(this.node);
this.form.controls.title.statusChanges
.pipe(takeUntil(this.onDestroy$))
.subscribe(
() =>
(this._titleErrorTranslationKey = this.form.controls.title.errors?.empty
? 'LIBRARY.ERRORS.ONLY_SPACES'
: 'LIBRARY.ERRORS.TITLE_TOO_LONG_OR_MISSING')
);
this.form.controls['title'].valueChanges
.pipe(
debounceTime(300),
@@ -164,7 +187,12 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges, OnDestro
update() {
if (this.canUpdateLibrary && this.form.valid) {
this.form.markAsPristine();
this.store.dispatch(new UpdateLibraryAction(this.form.value));
this.store.dispatch(
new UpdateLibraryAction({
...this.form.value,
title: this.form.value.title.trim()
})
);
}
}
@@ -182,7 +210,7 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges, OnDestro
private findLibraryByTitle(libraryTitle: string): Observable<SitePaging | { list: { entries: any[] } }> {
return from(
this.queriesApi
.findSites(libraryTitle, {
.findSites(libraryTitle.trim(), {
maxItems: 1,
fields: ['title']
})
@@ -199,4 +227,8 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges, OnDestro
)
.subscribe(handle);
}
private validateEmptyName(control: FormControl<string>): ValidationErrors {
return control.value.length && !control.value.trim() ? { empty: true } : null;
}
}