mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-02 17:53:30 +00:00
AAE-46057 Stabilize form field status layout (#12165)
This commit is contained in:
@@ -20,6 +20,12 @@
|
||||
.mat-mdc-form-field-infix {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.adf-form-field-input:not(.adf-inplace-input-mat-form-field, .adf-people-cloud, .adf-cloud-group) {
|
||||
#{ms.$mat-form-field-subscript-wrapper} {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alfresco-tabs-widget {
|
||||
@@ -40,7 +46,7 @@
|
||||
|
||||
.adf-container-widget {
|
||||
.adf-form-field-input:not(.adf-inplace-input-mat-form-field, .adf-people-cloud, .adf-cloud-group) {
|
||||
margin-bottom: 35px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.adf-grid-list {
|
||||
@@ -265,7 +271,7 @@
|
||||
}
|
||||
|
||||
&-error-messages-container {
|
||||
min-height: 35px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&-error-messages-container-visible {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
&-single-column {
|
||||
display: flex;
|
||||
flex-wrap: inherit;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
gap: 1%;
|
||||
|
||||
@include flex.layout-bp(lt-md) {
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
|
||||
</mat-checkbox>
|
||||
<div class="adf-error-messages-container">
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget
|
||||
*ngIf="isInvalidFieldRequired() && isTouched()"
|
||||
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
|
||||
[error]="field.validationSummary"
|
||||
[required]="isInvalidFieldRequired() && isTouched() ? ('FORM.FIELD.REQUIRED' | translate) : ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { NgClass, NgIf } from '@angular/common';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -47,7 +47,7 @@ import { WidgetComponent } from '../widget.component';
|
||||
'(invalid)': 'event($event)',
|
||||
'(select)': 'event($event)'
|
||||
},
|
||||
imports: [NgClass, MatCheckboxModule, FormsModule, TranslatePipe, ErrorWidgetComponent, NgIf],
|
||||
imports: [NgClass, MatCheckboxModule, FormsModule, TranslatePipe, ErrorWidgetComponent],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class CheckboxWidgetComponent extends WidgetComponent {}
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
error-widget {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.adf-error {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&-widget-container {
|
||||
height: auto;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&-animate {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.adf-hyperlink-widget {
|
||||
padding: 0.4375em 0;
|
||||
border-top: 0.8438em solid transparent;
|
||||
margin-bottom: 20px;
|
||||
|
||||
a {
|
||||
color: var(--mat-sys-primary);
|
||||
|
||||
@@ -43,6 +43,6 @@
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
.adf-container-widget .adf-multiline-text-widget .adf-form-field-input.adf-has-counter {
|
||||
margin-bottom: 44px;
|
||||
.adf-container-widget .adf-multiline-text-widget mat-form-field.adf-form-field-input.adf-has-counter {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
}
|
||||
|
||||
&-row-action {
|
||||
margin-left: 10px;
|
||||
margin-inline-start: 10px;
|
||||
margin-block-end: 35px;
|
||||
}
|
||||
|
||||
&-row-limit {
|
||||
|
||||
@@ -17,6 +17,7 @@ $mat-button: '.mat-mdc-button';
|
||||
$mat-button-label: '.mdc-button__label';
|
||||
$mat-form-field: '.mat-mdc-form-field';
|
||||
$mat-form-field-wrapper: '.mat-mdc-text-field-wrapper';
|
||||
$mat-form-field-subscript-wrapper: '.mat-mdc-form-field-subscript-wrapper';
|
||||
$mat-line-ripple: '.mdc-line-ripple';
|
||||
$mat-form-field-prefix: '.mat-mdc-form-field-text-prefix';
|
||||
$mat-form-field-suffix: '.mat-mdc-form-field-text-suffix';
|
||||
|
||||
+27
-19
@@ -1,21 +1,26 @@
|
||||
<div class="adf-attach-file-widget-container">
|
||||
<div class="adf-attach-widget {{field.className}}"
|
||||
[class.adf-readonly]="field.readOnly">
|
||||
<label class="adf-label" [attr.for]="field.id + '-label'">{{field.name}}
|
||||
<span class="adf-asterisk" *ngIf="isRequired()">*</span>
|
||||
<div class="adf-attach-widget {{ field.className }}" [class.adf-readonly]="field.readOnly">
|
||||
<label class="adf-label" [attr.for]="field.id + '-label'"
|
||||
>{{ field.name }}
|
||||
@if (isRequired()) {
|
||||
<span class="adf-asterisk">*</span>
|
||||
}
|
||||
</label>
|
||||
<div class="adf-attach-widget-container" (focusout)="markAsTouched()">
|
||||
<div class="adf-attach-widget__menu-upload" *ngIf="isUploadButtonVisible()">
|
||||
<button
|
||||
(click)="openSelectDialog()"
|
||||
mat-raised-button
|
||||
class="adf-attach-widget__menu-upload__button"
|
||||
[id]="field.id"
|
||||
[title]="field.tooltip">
|
||||
@if (isUploadButtonVisible()) {
|
||||
<div class="adf-attach-widget__menu-upload">
|
||||
<button
|
||||
(click)="openSelectDialog()"
|
||||
mat-raised-button
|
||||
class="adf-attach-widget__menu-upload__button"
|
||||
[id]="field.id"
|
||||
[title]="field.tooltip"
|
||||
>
|
||||
{{ 'FORM.FIELD.ATTACH' | translate }}
|
||||
<mat-icon class="adf-attach-widget__menu-upload__button__icon" [adf-icon]="getWidgetIcon()" />
|
||||
</button>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,12 +39,15 @@
|
||||
(contentModelFileHandler)="contentModelFormFileHandler($event)"
|
||||
(removeAttachFile)="onRemoveAttachFile($event)"
|
||||
/>
|
||||
<div *ngIf="!hasFile && field.readOnly" id="{{'adf-attach-empty-list-'+field.id}}">
|
||||
{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}
|
||||
</div>
|
||||
|
||||
@if (!hasFile && field.readOnly) {
|
||||
<div id="{{ 'adf-attach-empty-list-' + field.id }}">
|
||||
{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget *ngIf="!field.isValid && isTouched() && !isSelected()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
|
||||
<error-widget
|
||||
[error]="field.validationSummary"
|
||||
[required]="!field.isValid && isTouched() && !isSelected() ? ('FORM.FIELD.REQUIRED' | translate) : ''"
|
||||
/>
|
||||
</div>
|
||||
|
||||
+8
-16
@@ -1,31 +1,23 @@
|
||||
<div class="adf-data-table-widget-container">
|
||||
<div class="adf-data-table-widget-label">
|
||||
<label
|
||||
class="adf-label"
|
||||
[class.adf-left-label]="field.leftLabels"
|
||||
[attr.for]="field.id">
|
||||
{{field.name | translate }}
|
||||
</label>
|
||||
<label class="adf-label" [class.adf-left-label]="field.leftLabels" [attr.for]="field.id"> {{field.name | translate }} </label>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!previewState; else previewTemplate">
|
||||
@if (!previewState) {
|
||||
<adf-datatable data-automation-id="adf-data-table-widget" [data]="dataSource">
|
||||
<adf-no-content-template>
|
||||
<ng-template>
|
||||
<adf-empty-content
|
||||
icon="border_all"
|
||||
[title]="'FORM.FIELD.DATA_TABLE_EMPTY_CONTENT' | translate" />
|
||||
<adf-empty-content icon="border_all" [title]="'FORM.FIELD.DATA_TABLE_EMPTY_CONTENT' | translate" />
|
||||
</ng-template>
|
||||
</adf-no-content-template>
|
||||
</adf-datatable>
|
||||
|
||||
<error-widget *ngIf="dataTableLoadFailed"
|
||||
<error-widget
|
||||
class="adf-data-table-widget-failed-message"
|
||||
[required]="'FORM.FIELD.DATA_TABLE_LOAD_FAILED' | translate" />
|
||||
</ng-container>
|
||||
|
||||
<ng-template #previewTemplate>
|
||||
[required]="dataTableLoadFailed ? ('FORM.FIELD.DATA_TABLE_LOAD_FAILED' | translate) : ''"
|
||||
/>
|
||||
} @else {
|
||||
<adf-datatable data-automation-id="adf-data-table-widget-preview" />
|
||||
<div class="adf-preview-placeholder"></div>
|
||||
</ng-template>
|
||||
}
|
||||
</div>
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
.adf-data-table-widget-failed-message {
|
||||
display: block;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -283,7 +283,8 @@ describe('DataTableWidgetComponent', () => {
|
||||
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
|
||||
|
||||
assertData(mockCountryColumns, []);
|
||||
expect(failedErrorMsgElement).toBeNull();
|
||||
expect(failedErrorMsgElement).toBeTruthy();
|
||||
expect(failedErrorMsgElement.nativeElement.textContent.trim()).toBe('');
|
||||
});
|
||||
|
||||
it('path points to single object with appropriate schema definition', () => {
|
||||
@@ -294,7 +295,8 @@ describe('DataTableWidgetComponent', () => {
|
||||
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
|
||||
|
||||
assertData(mockCountryColumns, [mockEuropeCountriesRows[1]]);
|
||||
expect(failedErrorMsgElement).toBeNull();
|
||||
expect(failedErrorMsgElement).toBeTruthy();
|
||||
expect(failedErrorMsgElement.nativeElement.textContent.trim()).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+1
-2
@@ -27,7 +27,6 @@ import {
|
||||
NoContentTemplateDirective,
|
||||
EmptyContentComponent
|
||||
} from '@alfresco/adf-core';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { FormCloudService } from '../../../services/form-cloud.service';
|
||||
import { TaskVariableCloud } from '../../../models/task-variable-cloud.model';
|
||||
@@ -36,7 +35,7 @@ import { DataTablePathParserHelper } from './helpers/data-table-path-parser.help
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [NgIf, TranslatePipe, FormBaseModule, DataTableComponent, NoContentTemplateDirective, EmptyContentComponent],
|
||||
imports: [TranslatePipe, FormBaseModule, DataTableComponent, NoContentTemplateDirective, EmptyContentComponent],
|
||||
selector: 'data-table',
|
||||
templateUrl: './data-table.widget.html',
|
||||
styleUrls: ['./data-table.widget.scss'],
|
||||
|
||||
+8
-12
@@ -4,11 +4,13 @@
|
||||
[class.adf-readonly]="field.readOnly"
|
||||
[class.adf-left-label-input-container]="field.leftLabels"
|
||||
>
|
||||
<div *ngIf="field.leftLabels">
|
||||
<label class="adf-label adf-left-label" [attr.for]="field.id"
|
||||
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
|
||||
>
|
||||
</div>
|
||||
@if (field.leftLabels) {
|
||||
<div>
|
||||
<label class="adf-label adf-left-label" [attr.for]="field.id"
|
||||
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
|
||||
>
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<adf-cloud-group
|
||||
[mode]="mode"
|
||||
@@ -22,13 +24,7 @@
|
||||
[preSelectGroups]="preSelectGroup"
|
||||
(blur)="markAsTouched()"
|
||||
[attr.title]="field.tooltip"
|
||||
[label] = "field.name | translate"
|
||||
/>
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget
|
||||
class="adf-dropdown-required-message"
|
||||
*ngIf="isInvalidFieldRequired() && isTouched()"
|
||||
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"
|
||||
[label]="field.name | translate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
-2
@@ -141,8 +141,9 @@ describe('GroupCloudWidgetComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-error-text')).toBeTruthy();
|
||||
expect(element.querySelector('.adf-error-text').textContent).toContain('ADF_CLOUD_GROUPS.ERROR.NOT_FOUND');
|
||||
const errorMessages = element.querySelectorAll('.adf-error-text');
|
||||
expect(errorMessages.length).toBe(1);
|
||||
expect(errorMessages[0].textContent).toContain('ADF_CLOUD_GROUPS.ERROR.NOT_FOUND');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, DestroyRef, inject, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ErrorWidgetComponent, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { WidgetComponent } from '@alfresco/adf-core';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { ComponentSelectionMode } from '../../../../types';
|
||||
@@ -31,7 +31,7 @@ import { GroupCloudComponent } from '../../../../group/components/group-cloud.co
|
||||
|
||||
@Component({
|
||||
selector: 'group-cloud-widget',
|
||||
imports: [CommonModule, TranslatePipe, ErrorWidgetComponent, GroupCloudComponent],
|
||||
imports: [CommonModule, TranslatePipe, GroupCloudComponent],
|
||||
templateUrl: './group-cloud.widget.html',
|
||||
host: {
|
||||
'(click)': 'event($event)',
|
||||
|
||||
+13
-13
@@ -1,10 +1,16 @@
|
||||
<div class="adf-dropdown-widget {{field.className}}"
|
||||
[class.adf-invalid]="!field.isValid && isTouched()"
|
||||
[class.adf-readonly]="field.readOnly"
|
||||
[class.adf-left-label-input-container]="field.leftLabels">
|
||||
<div *ngIf="field.leftLabels">
|
||||
<label class="adf-label adf-left-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label>
|
||||
</div>
|
||||
<div
|
||||
class="adf-dropdown-widget {{field.className}}"
|
||||
[class.adf-invalid]="!field.isValid && isTouched()"
|
||||
[class.adf-readonly]="field.readOnly"
|
||||
[class.adf-left-label-input-container]="field.leftLabels"
|
||||
>
|
||||
@if (field.leftLabels) {
|
||||
<div>
|
||||
<label class="adf-label adf-left-label" [attr.for]="field.id"
|
||||
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
|
||||
>
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<adf-cloud-people
|
||||
[preSelectUsers]="preSelectUsers"
|
||||
@@ -21,11 +27,5 @@
|
||||
[attr.title]="field.tooltip"
|
||||
[label]="field.name | translate"
|
||||
/>
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget
|
||||
class="adf-dropdown-required-message"
|
||||
*ngIf="isInvalidFieldRequired() && isTouched()"
|
||||
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+3
-2
@@ -171,8 +171,9 @@ describe('PeopleCloudWidgetComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-error-text')).toBeTruthy();
|
||||
expect(element.querySelector('.adf-error-text').textContent).toContain('ADF_CLOUD_USERS.ERROR.NOT_FOUND');
|
||||
const errorMessages = element.querySelectorAll('.adf-error-text');
|
||||
expect(errorMessages.length).toBe(1);
|
||||
expect(errorMessages[0].textContent).toContain('ADF_CLOUD_USERS.ERROR.NOT_FOUND');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+2
-3
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, DestroyRef, inject, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ErrorWidgetComponent, WidgetComponent } from '@alfresco/adf-core';
|
||||
import { WidgetComponent } from '@alfresco/adf-core';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { ComponentSelectionMode } from '../../../../types';
|
||||
@@ -27,13 +27,12 @@ import { ReactivePreselectionService } from '../reactive-preselection.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { PeopleCloudComponent } from '../../../../people/components/people-cloud.component';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
@Component({
|
||||
selector: 'people-cloud-widget',
|
||||
imports: [CommonModule, TranslatePipe, ErrorWidgetComponent, PeopleCloudComponent, MatFormFieldModule],
|
||||
imports: [CommonModule, TranslatePipe, PeopleCloudComponent],
|
||||
templateUrl: './people-cloud.widget.html',
|
||||
host: {
|
||||
'(click)': 'event($event)',
|
||||
|
||||
-1
@@ -11,7 +11,6 @@
|
||||
}
|
||||
|
||||
&-radio-button-container-horizontal {
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
align-items: flex-start;
|
||||
|
||||
+43
-44
@@ -4,51 +4,50 @@
|
||||
>
|
||||
<div class="adf-cloud-upload-widget-container">
|
||||
<div>
|
||||
<mat-list *ngIf="hasFile">
|
||||
<mat-list-item class="adf-upload-files-row" *ngFor="let file of uploadedFiles">
|
||||
<img
|
||||
matListItemLine
|
||||
class="adf-upload-widget__icon"
|
||||
[id]="'file-'+file.id+'-icon'"
|
||||
[src]="getIcon(file.content.mimeType)"
|
||||
[alt]="mimeTypeIcon"
|
||||
(click)="fileClicked(file)"
|
||||
(keyup.enter)="fileClicked(file)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
<span
|
||||
class="adf-upload-widget__button adf-file"
|
||||
matLine
|
||||
id="{{'file-'+file.id}}"
|
||||
(click)="fileClicked(file)"
|
||||
(keyup.enter)="fileClicked(file)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>{{file.name}}</span
|
||||
>
|
||||
<button
|
||||
*ngIf="!field.readOnly"
|
||||
mat-icon-button
|
||||
[id]="'file-'+file.id+'-remove'"
|
||||
(click)="removeFile(file);"
|
||||
(keyup.enter)="removeFile(file);"
|
||||
>
|
||||
<mat-icon class="mat-24" adf-icon="highlight_off" />
|
||||
</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
@if (hasFile) {
|
||||
<mat-list>
|
||||
<mat-list-item class="adf-upload-files-row" *ngFor="let file of uploadedFiles">
|
||||
<img
|
||||
matListItemLine
|
||||
class="adf-upload-widget__icon"
|
||||
[id]="'file-'+file.id+'-icon'"
|
||||
[src]="getIcon(file.content.mimeType)"
|
||||
[alt]="mimeTypeIcon"
|
||||
(click)="fileClicked(file)"
|
||||
(keyup.enter)="fileClicked(file)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
<span
|
||||
class="adf-upload-widget__button adf-file"
|
||||
matLine
|
||||
id="{{'file-'+file.id}}"
|
||||
(click)="fileClicked(file)"
|
||||
(keyup.enter)="fileClicked(file)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>{{file.name}}</span
|
||||
>
|
||||
@if (!field.readOnly) {
|
||||
<button mat-icon-button [id]="'file-'+file.id+'-remove'" (click)="removeFile(file);" (keyup.enter)="removeFile(file);">
|
||||
<mat-icon class="mat-24" adf-icon="highlight_off" />
|
||||
</button>
|
||||
}
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div *ngIf="(!hasFile || multipleOption) && !field.readOnly">
|
||||
<button mat-raised-button (click)="uploadFiles.click()" [title]="field.tooltip">
|
||||
{{ 'FORM.FIELD.UPLOAD' | translate }}<mat-icon adf-icon="file_upload" />
|
||||
<input #uploadFiles [multiple]="multipleOption" type="file" [id]="field.form.nodeId" (change)="onFileChanged($event)" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!hasFile && field.readOnly">{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}</div>
|
||||
@if ((!hasFile || multipleOption) && !field.readOnly) {
|
||||
<div>
|
||||
<button mat-raised-button (click)="uploadFiles.click()" [title]="field.tooltip">
|
||||
{{ 'FORM.FIELD.UPLOAD' | translate }}<mat-icon adf-icon="file_upload" />
|
||||
<input #uploadFiles [multiple]="multipleOption" type="file" [id]="field.form.nodeId" (change)="onFileChanged($event)" />
|
||||
</button>
|
||||
</div>
|
||||
} @if (!hasFile && field.readOnly) {
|
||||
<div>{{ 'FORM.FIELD.NO_FILE_ATTACHED' | translate }}</div>
|
||||
}
|
||||
</div>
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
|
||||
<error-widget [error]="field.validationSummary" [required]="isInvalidFieldRequired() ? ('FORM.FIELD.REQUIRED' | translate) : ''" />
|
||||
</div>
|
||||
|
||||
+8
@@ -55,4 +55,12 @@ describe('UploadCloudWidgetComponent', () => {
|
||||
expect(eventSpy).toHaveBeenCalledWith(clickEvent);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render one reserved form field status area', () => {
|
||||
widget.field = new FormFieldModel(new FormModel(), {});
|
||||
fixture.detectChanges();
|
||||
|
||||
const statusAreas = fixture.nativeElement.querySelectorAll('error-widget');
|
||||
expect(statusAreas.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
<form>
|
||||
<mat-form-field class="adf-cloud-group adf-form-field-input" [class.adf-invalid]="hasError() && isDirty()">
|
||||
@if (label || required) { <mat-label><span>{{label}}</span></mat-label> }
|
||||
<mat-form-field subscriptSizing="dynamic" class="adf-cloud-group adf-form-field-input" [class.adf-invalid]="hasError() && isDirty()">
|
||||
@if (label || required) {
|
||||
<mat-label
|
||||
><span>{{ label }}</span></mat-label
|
||||
>
|
||||
}
|
||||
<mat-chip-grid [required]="required" [disabled]="isReadonly()" #groupChipList data-automation-id="adf-cloud-group-chip-list">
|
||||
<mat-chip-row
|
||||
*ngFor="let group of selectedGroups"
|
||||
[removable]="!(group.readonly)"
|
||||
[removable]="!group.readonly"
|
||||
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
|
||||
(removed)="onRemove(group)"
|
||||
[disabled]="readOnly || isValidationLoading()"
|
||||
title="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}">
|
||||
{{group.name}}
|
||||
<mat-icon *ngIf="!(group.readonly || readOnly)" matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name" adf-icon="cancel" />
|
||||
title="{{ (group.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"
|
||||
>
|
||||
{{ group.name }}
|
||||
@if (!(group.readonly || readOnly)) {
|
||||
<mat-icon matChipRemove [attr.data-automation-id]="'adf-cloud-group-chip-remove-icon-' + group.name" adf-icon="cancel" />
|
||||
}
|
||||
</mat-chip-row>
|
||||
<input matInput
|
||||
[formControl]="searchGroupsControl"
|
||||
[matAutocomplete]="auto"
|
||||
[matChipInputFor]="groupChipList"
|
||||
[placeholder]="isReadonly() ? '' : (title | translate)"
|
||||
[required]="required"
|
||||
(focus)="setFocus(true)"
|
||||
(blur)="setFocus(false); markAsTouched()"
|
||||
class="adf-group-input"
|
||||
data-automation-id="adf-cloud-group-search-input" #groupInput>
|
||||
<input
|
||||
matInput
|
||||
[formControl]="searchGroupsControl"
|
||||
[matAutocomplete]="auto"
|
||||
[matChipInputFor]="groupChipList"
|
||||
[placeholder]="isReadonly() ? '' : (title | translate)"
|
||||
[required]="required"
|
||||
(focus)="setFocus(true)"
|
||||
(blur)="setFocus(false); markAsTouched()"
|
||||
class="adf-group-input"
|
||||
data-automation-id="adf-cloud-group-search-input"
|
||||
#groupInput
|
||||
/>
|
||||
</mat-chip-grid>
|
||||
|
||||
<mat-autocomplete
|
||||
@@ -30,57 +40,77 @@
|
||||
class="adf-cloud-group-list"
|
||||
(optionSelected)="onSelect($event.option.value)"
|
||||
[displayWith]="getDisplayName"
|
||||
data-automation-id="adf-cloud-group-autocomplete">
|
||||
<ng-container *ngIf="(searchGroups$ | async)?.length else noResults">
|
||||
<mat-option *ngFor="let group of searchGroups$ | async; let i = index" [value]="group"
|
||||
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
|
||||
class="adf-cloud-group-option-active">
|
||||
<div
|
||||
class="adf-cloud-group-row"
|
||||
id="adf-group-{{i}}"
|
||||
data-automation-id="adf-cloud-group-row">
|
||||
<button class="adf-group-short-name" mat-fab>{{getGroupNameInitials(group)}}</button>
|
||||
<span>{{group.name}}</span>
|
||||
data-automation-id="adf-cloud-group-autocomplete"
|
||||
>
|
||||
@if ((searchGroups$ | async)?.length) {
|
||||
<mat-option
|
||||
*ngFor="let group of searchGroups$ | async; let i = index"
|
||||
[value]="group"
|
||||
[attr.data-automation-id]="'adf-cloud-group-chip-' + group.name"
|
||||
class="adf-cloud-group-option-active"
|
||||
>
|
||||
<div class="adf-cloud-group-row" id="adf-group-{{ i }}" data-automation-id="adf-cloud-group-row">
|
||||
<button class="adf-group-short-name" mat-fab>{{ getGroupNameInitials(group) }}</button>
|
||||
<span>{{ group.name }}</span>
|
||||
</div>
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
} @else {
|
||||
<ng-container [ngTemplateOutlet]="noResults" />
|
||||
}
|
||||
<ng-template #noResults>
|
||||
<mat-option *ngIf="searchGroupsControl.hasError('searchTypingError') && !searchLoading" disabled
|
||||
class="adf-cloud-group-option-not-active"
|
||||
data-automation-id="adf-cloud-group-no-results">
|
||||
<span> {{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</span>
|
||||
</mat-option>
|
||||
@if (searchGroupsControl.hasError('searchTypingError') && !searchLoading) {
|
||||
<mat-option disabled class="adf-cloud-group-option-not-active" data-automation-id="adf-cloud-group-no-results">
|
||||
<span> {{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</span>
|
||||
</mat-option>
|
||||
}
|
||||
</ng-template>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
<mat-progress-bar *ngIf="validationLoading" mode="indeterminate" />
|
||||
|
||||
<div class="adf-error-container adf-error-messages-container">
|
||||
<mat-error *ngIf="hasPreselectError() && !isValidationLoading()" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchGroupsControl.hasError('pattern')" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}</div>
|
||||
@if (validationLoading) {
|
||||
<mat-progress-bar mode="indeterminate" />
|
||||
}
|
||||
@if (hasPreselectError() && !isValidationLoading()) {
|
||||
<mat-error class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchGroupsControl.hasError('maxlength')" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchGroupsControl.hasError('minlength')" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="(searchGroupsControl.hasError('required') || groupChipsCtrl.hasError('required')) && isDirty()"
|
||||
class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }} </div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchGroupsControl.hasError('searchTypingError') && !this.isFocused"
|
||||
data-automation-id="invalid-groups-typing-error" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchGroupsControl.hasError('pattern')) {
|
||||
<mat-error class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchGroupsControl.hasError('maxlength')) {
|
||||
<mat-error class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchGroupsControl.hasError('minlength')) {
|
||||
<mat-error class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if ((searchGroupsControl.hasError('required') || groupChipsCtrl.hasError('required')) && isDirty()) {
|
||||
<mat-error class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }}</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchGroupsControl.hasError('searchTypingError') && !this.isFocused) {
|
||||
<mat-error data-automation-id="invalid-groups-typing-error" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_GROUPS.ERROR.NOT_FOUND' | translate }}</div>
|
||||
</mat-error>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -57,10 +57,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.adf-error-messages-container .adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
.adf-error-messages-container {
|
||||
.adf-error-icon {
|
||||
@include mixins.adf-error-icon;
|
||||
}
|
||||
|
||||
.adf-error-messages-container .adf-error {
|
||||
animation: slide-down-fade-in 300ms cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
.adf-error {
|
||||
animation: slide-down-fade-in 300ms cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatChipHarness } from '@angular/material/chips/testing';
|
||||
import { MatIconHarness } from '@angular/material/icon/testing';
|
||||
import { MatInputHarness } from '@angular/material/input/testing';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MatProgressBar } from '@angular/material/progress-bar';
|
||||
|
||||
describe('GroupCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
@@ -98,6 +100,22 @@ describe('GroupCloudComponent', () => {
|
||||
expect(await inputElement.getPlaceholder()).toEqual('');
|
||||
});
|
||||
|
||||
it('should use dynamic form field subscript sizing', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const formField = fixture.debugElement.query(By.directive(MatFormField)).componentInstance as MatFormField;
|
||||
expect(formField.subscriptSizing).toBe('dynamic');
|
||||
});
|
||||
|
||||
it('should render validation progress inside the reserved status area', () => {
|
||||
component.validationLoading = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const progressBar = fixture.debugElement.query(By.directive(MatProgressBar));
|
||||
|
||||
expect(progressBar.parent.classes['adf-error-messages-container']).toBeTrue();
|
||||
});
|
||||
|
||||
describe('Search group', () => {
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
class="adf-people-cloud adf-form-field-input"
|
||||
[class.adf-invalid]="hasError() && isDirty()"
|
||||
>
|
||||
<mat-label *ngIf="!title">
|
||||
<span>{{label}}</span>
|
||||
</mat-label>
|
||||
<mat-label *ngIf="title">{{ title | translate }}</mat-label>
|
||||
@if (!title) {
|
||||
<mat-label>
|
||||
<span>{{ label }}</span>
|
||||
</mat-label>
|
||||
}
|
||||
@if (title) {
|
||||
<mat-label>{{ title | translate }}</mat-label>
|
||||
}
|
||||
|
||||
<mat-chip-grid [required]="required" [disabled]="isReadonly()" #userMultipleChipList data-automation-id="adf-cloud-people-chip-list">
|
||||
<mat-chip-row
|
||||
@@ -17,10 +21,12 @@
|
||||
(removed)="onRemove(user)"
|
||||
[disabled]="isReadonly() || isValidationLoading()"
|
||||
title="{{ (user.readonly ? 'ADF_CLOUD_GROUPS.MANDATORY' : '') | translate }}"
|
||||
[matTooltip]="showFullNameOnHover ? (user | fullName : true) : user.email"
|
||||
[matTooltip]="showFullNameOnHover ? (user | fullName: true) : user.email"
|
||||
>
|
||||
{{ user | fullName }}
|
||||
<mat-icon matChipRemove *ngIf="!(user.readonly || readOnly)" [attr.data-automation-id]="'adf-people-cloud-chip-remove-icon-' + user.username" adf-icon="cancel" />
|
||||
@if (!(user.readonly || readOnly)) {
|
||||
<mat-icon matChipRemove [attr.data-automation-id]="'adf-people-cloud-chip-remove-icon-' + user.username" adf-icon="cancel" />
|
||||
}
|
||||
</mat-chip-row>
|
||||
<input
|
||||
matInput
|
||||
@@ -44,64 +50,73 @@
|
||||
(optionSelected)="onSelect($event.option.value)"
|
||||
[displayWith]="getDisplayName"
|
||||
>
|
||||
<ng-container *ngIf="(searchUsers$ | async)?.length; else noResults">
|
||||
@if ((searchUsers$ | async)?.length) {
|
||||
<mat-option *ngFor="let user of searchUsers$ | async; let i = index" [value]="user" class="adf-people-cloud-option-active">
|
||||
<div class="adf-people-cloud-row" id="adf-people-cloud-user-{{ user.username }}" data-automation-id="adf-people-cloud-row">
|
||||
<div [outerHTML]="user | usernameInitials : 'adf-people-cloud-pic'"></div>
|
||||
<span class="adf-people-label-name"> {{ user | fullName : true }}</span>
|
||||
<div [outerHTML]="user | usernameInitials: 'adf-people-cloud-pic'"></div>
|
||||
<span class="adf-people-label-name"> {{ user | fullName: true }}</span>
|
||||
</div>
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
} @else {
|
||||
<ng-container [ngTemplateOutlet]="noResults" />
|
||||
}
|
||||
<ng-template #noResults>
|
||||
<mat-option
|
||||
*ngIf="searchUserCtrl.hasError('searchTypingError') && !searchLoading"
|
||||
disabled
|
||||
class="adf-people-cloud-option-not-active"
|
||||
data-automation-id="adf-people-cloud-no-results"
|
||||
>
|
||||
<span> {{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: searchedValue } }}</span>
|
||||
</mat-option>
|
||||
@if (searchUserCtrl.hasError('searchTypingError') && !searchLoading) {
|
||||
<mat-option disabled class="adf-people-cloud-option-not-active" data-automation-id="adf-people-cloud-no-results">
|
||||
<span> {{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate: { userName: searchedValue } }}</span>
|
||||
</mat-option>
|
||||
}
|
||||
</ng-template>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-progress-bar *ngIf="validationLoading" mode="indeterminate" />
|
||||
|
||||
<div class="adf-error-container adf-error-messages-container" *ngIf="showErrors">
|
||||
<mat-error *ngIf="hasPreselectError() && !isValidationLoading()" class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: validateUsersMessage } }}</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchUserCtrl.hasError('pattern')" class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate : { pattern: getValidationPattern() } }}</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchUserCtrl.hasError('maxlength')" class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate : { requiredLength: getValidationMaxLength() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
<mat-error *ngIf="searchUserCtrl.hasError('minlength')" class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate : { requiredLength: getValidationMinLength() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="(searchUserCtrl.hasError('required') || userChipsCtrl.hasError('required')) && isDirty()"
|
||||
class="adf-error adf-error-animate"
|
||||
>
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }}</div>
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="searchUserCtrl.hasError('searchTypingError') && !this.isFocused"
|
||||
data-automation-id="invalid-users-typing-error"
|
||||
class="adf-error adf-error-animate"
|
||||
>
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate : { userName: searchedValue } }}</div>
|
||||
</mat-error>
|
||||
<div class="adf-error-container adf-error-messages-container">
|
||||
@if (validationLoading) {
|
||||
<mat-progress-bar mode="indeterminate" />
|
||||
}
|
||||
@if (showErrors) {
|
||||
@if (hasPreselectError() && !isValidationLoading()) {
|
||||
<mat-error class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate: { userName: validateUsersMessage } }}</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchUserCtrl.hasError('pattern')) {
|
||||
<mat-error class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_PATTERN' | translate: { pattern: getValidationPattern() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchUserCtrl.hasError('maxlength')) {
|
||||
<mat-error class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MAX_LENGTH' | translate: { requiredLength: getValidationMaxLength() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchUserCtrl.hasError('minlength')) {
|
||||
<mat-error class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">
|
||||
{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.INVALID_MIN_LENGTH' | translate: { requiredLength: getValidationMinLength() } }}
|
||||
</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if ((searchUserCtrl.hasError('required') || userChipsCtrl.hasError('required')) && isDirty()) {
|
||||
<mat-error class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_PEOPLE_GROUPS.ERROR.REQUIRED' | translate }}</div>
|
||||
</mat-error>
|
||||
}
|
||||
@if (searchUserCtrl.hasError('searchTypingError') && !this.isFocused) {
|
||||
<mat-error data-automation-id="invalid-users-typing-error" class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ 'ADF_CLOUD_USERS.ERROR.NOT_FOUND' | translate: { userName: searchedValue } }}</div>
|
||||
</mat-error>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -27,6 +27,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatChipHarness } from '@angular/material/chips/testing';
|
||||
import { MatInputHarness } from '@angular/material/input/testing';
|
||||
import { MatFormFieldHarness } from '@angular/material/form-field/testing';
|
||||
import { MatProgressBar } from '@angular/material/progress-bar';
|
||||
import { IdentityUserService } from '../services/identity-user.service';
|
||||
|
||||
describe('PeopleCloudComponent', () => {
|
||||
@@ -99,6 +100,19 @@ describe('PeopleCloudComponent', () => {
|
||||
expect(await inputField.getLabel()).toEqual('TITLE_KEY');
|
||||
});
|
||||
|
||||
it('should use dynamic form field subscript sizing by default', () => {
|
||||
expect(component.formFieldSubscriptSizing).toBe('dynamic');
|
||||
});
|
||||
|
||||
it('should render validation progress inside the reserved status area', () => {
|
||||
component.validationLoading = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const progressBar = fixture.debugElement.query(By.directive(MatProgressBar));
|
||||
|
||||
expect(progressBar.parent.classes['adf-error-messages-container']).toBeTrue();
|
||||
});
|
||||
|
||||
describe('Search user', () => {
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -169,7 +169,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, AfterViewInit {
|
||||
* Material form field subscript sizing (fixed / dynamic)
|
||||
*/
|
||||
@Input()
|
||||
formFieldSubscriptSizing: SubscriptSizing = 'fixed';
|
||||
formFieldSubscriptSizing: SubscriptSizing = 'dynamic';
|
||||
|
||||
/**
|
||||
* Show errors under the form field
|
||||
|
||||
Reference in New Issue
Block a user