[ACS-9327] Add prohibited symbols validation for Categories dialog (#10985)

* [ACS-9327] Add prohibited symbols validation for Categories dialog

* [ACS-9327] add validator for ending dot

* [ACS-9327] use endsWith

* [ACS-9327] cr fix

* [ACS-9327] add appropriate error message
This commit is contained in:
Mykyta Maliarchuk
2025-07-07 10:12:49 +02:00
committed by GitHub
parent 9bed60befc
commit 54fd097fab
4 changed files with 49 additions and 10 deletions

View File

@@ -6,7 +6,7 @@
placeholder="{{'CATEGORIES_MANAGEMENT.CATEGORIES_SEARCH_PLACEHOLDER' | translate }}" placeholder="{{'CATEGORIES_MANAGEMENT.CATEGORIES_SEARCH_PLACEHOLDER' | translate }}"
adf-auto-focus adf-auto-focus
/> />
<mat-error *ngIf="categoryNameControl.invalid">{{ categoryNameErrorMessageKey | translate }}</mat-error> <mat-error *ngIf="categoryNameControl.invalid && categoryNameControl.touched">{{ categoryNameErrorMessageKey | translate }}</mat-error>
</div> </div>
<div class="adf-categories-list" *ngIf="categories?.length > 0" [class.adf-categories-list-fixed]="!categoryNameControlVisible"> <div class="adf-categories-list" *ngIf="categories?.length > 0" [class.adf-categories-list-fixed]="!categoryNameControlVisible">
<span <span

View File

@@ -303,12 +303,6 @@ describe('CategoriesManagementComponent', () => {
expect(component.categoryNameControl.hasValidator(Validators.required)).toBeFalse(); expect(component.categoryNameControl.hasValidator(Validators.required)).toBeFalse();
}); });
it('should display validation error when searching for empty category', fakeAsync(() => {
typeCategory(' ');
expect(getFirstError()).toBe('CATEGORIES_MANAGEMENT.ERRORS.EMPTY_CATEGORY');
}));
it('should clear categories and hide category control when classifiable aspect is removed', () => { it('should clear categories and hide category control when classifiable aspect is removed', () => {
const controlVisibilityChangeSpy = spyOn(component.categoryNameControlVisibleChange, 'emit').and.callThrough(); const controlVisibilityChangeSpy = spyOn(component.categoryNameControlVisibleChange, 'emit').and.callThrough();
classifiableChangedSubject.next(); classifiableChangedSubject.next();
@@ -523,6 +517,30 @@ describe('CategoriesManagementComponent', () => {
expect(getCreateCategoryLabel().hidden).toBeTrue(); expect(getCreateCategoryLabel().hidden).toBeTrue();
})); }));
it('should display validation error when prohibited symbol entered', fakeAsync(() => {
typeCategory('category:name');
component.categoryNameControl.markAsTouched();
fixture.detectChanges();
expect(getFirstError()).toBe('CATEGORIES_MANAGEMENT.ERRORS.SPECIAL_CHARACTERS');
}));
it('should display validation error when dot placed in the end', fakeAsync(() => {
typeCategory('category.');
component.categoryNameControl.markAsTouched();
fixture.detectChanges();
expect(getFirstError()).toBe('CATEGORIES_MANAGEMENT.ERRORS.ENDS_WITH_DOT');
}));
it('should not display validation error when dot used in positions other than the end', fakeAsync(() => {
typeCategory('.category.name');
component.categoryNameControl.markAsTouched();
fixture.detectChanges();
expect(component.categoryNameControl.valid).toBeTrue();
}));
}); });
}); });
}); });

View File

@@ -49,6 +49,8 @@ interface CategoryNameControlErrors {
duplicatedCategory?: boolean; duplicatedCategory?: boolean;
emptyCategory?: boolean; emptyCategory?: boolean;
required?: boolean; required?: boolean;
specialCharacters?: boolean;
endsWithDot?: boolean;
} }
@Component({ @Component({
@@ -73,14 +75,22 @@ export class CategoriesManagementComponent implements OnInit, OnDestroy {
['duplicatedExistingCategory', 'ALREADY_EXISTS'], ['duplicatedExistingCategory', 'ALREADY_EXISTS'],
['duplicatedCategory', 'DUPLICATED_CATEGORY'], ['duplicatedCategory', 'DUPLICATED_CATEGORY'],
['emptyCategory', 'EMPTY_CATEGORY'], ['emptyCategory', 'EMPTY_CATEGORY'],
['required', 'REQUIRED'] ['required', 'REQUIRED'],
['specialCharacters', 'SPECIAL_CHARACTERS'],
['endsWithDot', 'ENDS_WITH_DOT']
]); ]);
private existingCategoryLoaded$ = new Subject<void>(); private existingCategoryLoaded$ = new Subject<void>();
private cancelExistingCategoriesLoading$ = new Subject<void>(); private cancelExistingCategoriesLoading$ = new Subject<void>();
private _categoryNameControl = new FormControl<string>( private _categoryNameControl = new FormControl<string>(
'', '',
[this.validateIfNotAlreadyAdded.bind(this), this.validateEmptyCategory, Validators.required], [
this.validateIfNotAlreadyAdded.bind(this),
this.validateEmptyCategory,
this.validateSpecialCharacters,
this.validateEndsWithDot,
Validators.required
],
this.validateIfNotAlreadyCreated.bind(this) this.validateIfNotAlreadyCreated.bind(this)
); );
private _existingCategories: Category[]; private _existingCategories: Category[];
@@ -358,6 +368,15 @@ export class CategoriesManagementComponent implements OnInit, OnDestroy {
return categoryNameControl.value.length && !categoryNameControl.value.trim() ? { emptyCategory: true } : null; return categoryNameControl.value.length && !categoryNameControl.value.trim() ? { emptyCategory: true } : null;
} }
private validateSpecialCharacters(categoryNameControl: FormControl<string>): CategoryNameControlErrors | null {
const specialSymbolsRegex = /[:"\\|<>/?*]/;
return categoryNameControl.value.length && specialSymbolsRegex.test(categoryNameControl.value) ? { specialCharacters: true } : null;
}
private validateEndsWithDot(categoryNameControl: FormControl<string>): CategoryNameControlErrors | null {
return categoryNameControl.value.trim().endsWith('.') ? { endsWithDot: true } : null;
}
private setCategoryNameControlErrorMessageKey() { private setCategoryNameControlErrorMessageKey() {
this._categoryNameErrorMessageKey = this.categoryNameControl.invalid this._categoryNameErrorMessageKey = this.categoryNameControl.invalid
? `CATEGORIES_MANAGEMENT.ERRORS.${this.nameErrorMessagesByErrors.get( ? `CATEGORIES_MANAGEMENT.ERRORS.${this.nameErrorMessagesByErrors.get(

View File

@@ -183,7 +183,9 @@
"ALREADY_EXISTS": "Category already exists", "ALREADY_EXISTS": "Category already exists",
"DUPLICATED_CATEGORY": "Category is already added", "DUPLICATED_CATEGORY": "Category is already added",
"CREATE_CATEGORIES": "Error while creating categories", "CREATE_CATEGORIES": "Error while creating categories",
"EXISTING_CATEGORIES": "Some categories already exist" "EXISTING_CATEGORIES": "Some categories already exist",
"SPECIAL_CHARACTERS": "Category name cannot contain prohibited characters",
"ENDS_WITH_DOT": "Category name cannot end with a dot"
}, },
"CATEGORIES_SEARCH_PLACEHOLDER": "Search Categories" "CATEGORIES_SEARCH_PLACEHOLDER": "Search Categories"
}, },