Revert "AAE-12086 The error message is shown for completed task with read-onl…" (#9684)

This reverts commit d8f1946988.
This commit is contained in:
Wiktor Danielewski
2024-05-16 15:57:58 +02:00
committed by GitHub
parent d8f1946988
commit c71d8da9fe
3 changed files with 82 additions and 129 deletions

View File

@@ -1,12 +1,8 @@
<div <div class="adf-dropdown-widget {{field.className}}"
class="adf-dropdown-widget {{field.className}}" [class.adf-invalid]="(!field.isValid && isTouched()) || isRestApiFailed" [class.adf-readonly]="field.readOnly" [class.adf-left-label-input-container]="field.leftLabels">
[class.adf-invalid]="(!field.isValid && isTouched()) || isRestApiFailed"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels"
>
<div class="adf-dropdown-widget-top-labels"> <div class="adf-dropdown-widget-top-labels">
<label class="adf-label" [attr.for]="field.id" [class.adf-left-label]="field.leftLabels" <label class="adf-label" [attr.for]="field.id" [class.adf-left-label]="field.leftLabels">{{field.name | translate }}<span class="adf-asterisk"
>{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span> *ngIf="isRequired()">*</span>
</label> </label>
</div> </div>
<div> <div>
@@ -14,48 +10,36 @@
<mat-label *ngIf="getDefaultOption(list$ | async) as defaultOption"> <mat-label *ngIf="getDefaultOption(list$ | async) as defaultOption">
{{ defaultOption.name }} {{ defaultOption.name }}
</mat-label> </mat-label>
<mat-select <mat-select class="adf-select"
class="adf-select" [id]="field.id"
[id]="field.id" [(ngModel)]="field.value"
[(ngModel)]="field.value" [disabled]="field.readOnly"
[disabled]="field.readOnly" [compareWith]="compareDropdownValues"
[compareWith]="compareDropdownValues" (ngModelChange)="selectionChangedForField(field)"
(ngModelChange)="selectionChangedForField(field)" [matTooltip]="field.tooltip"
[matTooltip]="field.tooltip" [required]="isRequired()"
[required]="isRequired()" panelClass="adf-select-filter"
panelClass="adf-select-filter" (blur)="markAsTouched()"
(blur)="markAsTouched()" matTooltipPosition="above"
matTooltipPosition="above" matTooltipShowDelay="1000"
matTooltipShowDelay="1000" [multiple]="field.hasMultipleValues">
[multiple]="field.hasMultipleValues"
>
<adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)"></adf-select-filter-input> <adf-select-filter-input *ngIf="showInputFilter" (change)="filter$.next($event)"></adf-select-filter-input>
<mat-option *ngFor="let opt of list$ | async" [value]="getOptionValue(opt, field.value)" [id]="opt.id"> <mat-option *ngFor="let opt of list$ | async"
{{opt.name}} [value]="getOptionValue(opt, field.value)"
</mat-option> [id]="opt.id">{{opt.name}}
<mat-option id="readonlyOption" *ngIf="isReadOnlyType()" [value]="field.value">
{{field.value}}
</mat-option> </mat-option>
<mat-option id="readonlyOption" *ngIf="isReadOnlyType()" [value]="field.value">{{field.value}}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<div *ngIf="!previewState && !field.readOnly"> <div *ngIf="!previewState">
<error-widget [error]="field.validationSummary"></error-widget> <error-widget [error]="field.validationSummary"></error-widget>
<error-widget <error-widget class="adf-dropdown-required-message" *ngIf="showRequiredMessage()"
class="adf-dropdown-required-message" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
*ngIf="showRequiredMessage()" <error-widget class="adf-dropdown-failed-message" *ngIf="isRestApiFailed"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" required="{{ 'FORM.FIELD.REST_API_FAILED' | translate: { hostname: restApiHostName } }}"></error-widget>
></error-widget> <error-widget class="adf-dropdown-failed-message" *ngIf="variableOptionsFailed"
<error-widget required="{{ 'FORM.FIELD.VARIABLE_DROPDOWN_OPTIONS_FAILED' | translate }}"></error-widget>
class="adf-dropdown-failed-message"
*ngIf="isRestApiFailed"
required="{{ 'FORM.FIELD.REST_API_FAILED' | translate: { hostname: restApiHostName } }}"
></error-widget>
<error-widget
class="adf-dropdown-failed-message"
*ngIf="variableOptionsFailed"
required="{{ 'FORM.FIELD.VARIABLE_DROPDOWN_OPTIONS_FAILED' | translate }}"
></error-widget>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -64,10 +64,11 @@ describe('DropdownCloudWidgetComponent', () => {
describe('Simple Dropdown', () => { describe('Simple Dropdown', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',
readOnly: false,
restUrl: 'https://fake-rest-url', restUrl: 'https://fake-rest-url',
options: [{ id: 'empty', name: 'Choose one...' }] options: [{ id: 'empty', name: 'Choose one...' }]
}); });
@@ -119,18 +120,6 @@ describe('DropdownCloudWidgetComponent', () => {
expect(await allOptions[2].getText()).toEqual('option_3'); expect(await allOptions[2].getText()).toEqual('option_3');
}); });
it('should NOT load data from restUrl when field is readonly', () => {
spyOn(formCloudService, 'getRestWidgetData');
widget.field.readOnly = true;
widget.field.restUrl = 'https://fake-rest-url';
widget.field.optionType = 'rest';
widget.field.restIdProperty = 'name';
widget.ngOnInit();
expect(formCloudService.getRestWidgetData).not.toHaveBeenCalled();
});
it('should show error message if the restUrl failed to fetch options', async () => { it('should show error message if the restUrl failed to fetch options', async () => {
const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(throwError('Failed to fetch options')); const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(throwError('Failed to fetch options'));
const errorIcon: string = 'error_outline'; const errorIcon: string = 'error_outline';
@@ -205,7 +194,7 @@ describe('DropdownCloudWidgetComponent', () => {
expect(widget.field.form.values['dropdown-id']).toEqual({ id: 'opt1', name: 'default1_value' }); expect(widget.field.form.values['dropdown-id']).toEqual({ id: 'opt1', name: 'default1_value' });
}); });
it('should NOT display required error for a non required dropdown when selecting the none option', async () => { it('should not display required error for a non required dropdown when selecting the none option', async () => {
widget.field.options = [{ id: 'empty', name: 'Choose empty' }, ...fakeOptionList]; widget.field.options = [{ id: 'empty', name: 'Choose empty' }, ...fakeOptionList];
widget.ngOnInit(); widget.ngOnInit();
@@ -220,7 +209,7 @@ describe('DropdownCloudWidgetComponent', () => {
expect(requiredErrorElement).toBeFalsy(); expect(requiredErrorElement).toBeFalsy();
}); });
it('should NOT display required error when selecting a valid option for a required dropdown', async () => { it('should not display required error when selecting a valid option for a required dropdown', async () => {
widget.field.required = true; widget.field.required = true;
widget.field.options = [{ id: 'empty', name: 'Choose empty' }, ...fakeOptionList]; widget.field.options = [{ id: 'empty', name: 'Choose empty' }, ...fakeOptionList];
@@ -235,7 +224,7 @@ describe('DropdownCloudWidgetComponent', () => {
expect(requiredErrorElement).toBeFalsy(); expect(requiredErrorElement).toBeFalsy();
}); });
it('should NOT have a value when switching from an available option to the None option', async () => { it('should not have a value when switching from an available option to the None option', async () => {
widget.field.options = [{ id: 'empty', name: 'This is a mock none option' }, ...fakeOptionList]; widget.field.options = [{ id: 'empty', name: 'This is a mock none option' }, ...fakeOptionList];
widget.ngOnInit(); widget.ngOnInit();
@@ -326,30 +315,15 @@ describe('DropdownCloudWidgetComponent', () => {
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text')); const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED'); expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED');
}); });
it('should NOT display a required error when dropdown is readonly', async () => {
widget.field.readOnly = true;
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-invalid')).toBeFalsy();
const dropdownSelect = element.querySelector('.adf-select');
dropdownSelect.dispatchEvent(new Event('blur'));
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-invalid')).toBeFalsy();
});
}); });
describe('filter', () => { describe('filter', () => {
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'option list', name: 'option list',
type: 'dropdown', type: 'dropdown',
readOnly: false,
options: filterOptionList options: filterOptionList
}); });
widget.ngOnInit(); widget.ngOnInit();
@@ -396,10 +370,11 @@ describe('DropdownCloudWidgetComponent', () => {
describe('multiple selection', () => { describe('multiple selection', () => {
it('should show preselected option', async () => { it('should show preselected option', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
options: fakeOptionList, options: fakeOptionList,
selectionType: 'multiple', selectionType: 'multiple',
value: [ value: [
@@ -414,10 +389,11 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
it('should support multiple options', async () => { it('should support multiple options', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
selectionType: 'multiple', selectionType: 'multiple',
options: fakeOptionList options: fakeOptionList
}); });
@@ -432,10 +408,11 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
it('should show preselected option for rest options', async () => { it('should show preselected option for rest options', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
restUrl: 'https://fake-rest-url', restUrl: 'https://fake-rest-url',
optionType: 'rest', optionType: 'rest',
selectionType: 'multiple', selectionType: 'multiple',
@@ -471,10 +448,11 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
it('should support multiple options for rest options', async () => { it('should support multiple options for rest options', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'date-name', name: 'date-name',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
restUrl: 'https://fake-rest-url', restUrl: 'https://fake-rest-url',
optionType: 'rest', optionType: 'rest',
selectionType: 'multiple' selectionType: 'multiple'
@@ -520,10 +498,11 @@ describe('DropdownCloudWidgetComponent', () => {
validate: () => true validate: () => true
}); });
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'child-dropdown-id', id: 'child-dropdown-id',
name: 'child-dropdown', name: 'child-dropdown',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
optionType: 'rest', optionType: 'rest',
restUrl: 'myFakeDomain.com/cities?country=${parentDropdown}', restUrl: 'myFakeDomain.com/cities?country=${parentDropdown}',
rule: { rule: {
@@ -626,10 +605,11 @@ describe('DropdownCloudWidgetComponent', () => {
const parentDropdown = new FormFieldModel(new FormModel(), { id: 'parentDropdown', type: 'dropdown' }); const parentDropdown = new FormFieldModel(new FormModel(), { id: 'parentDropdown', type: 'dropdown' });
beforeEach(() => { beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'child-dropdown-id', id: 'child-dropdown-id',
name: 'child-dropdown', name: 'child-dropdown',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
optionType: 'manual', optionType: 'manual',
rule: { rule: {
ruleOn: 'parentDropdown', ruleOn: 'parentDropdown',
@@ -669,7 +649,7 @@ describe('DropdownCloudWidgetComponent', () => {
}); });
describe('Manual - On parent value changes (chain)', () => { describe('Manual - On parent value changes (chain)', () => {
it('should reset the current value when it NOT part of the available options', () => { it('should reset the current value when it not part of the available options', () => {
widget.field.options = mockConditionalEntries[1].options; widget.field.options = mockConditionalEntries[1].options;
widget.field.value = 'non-existent-value'; widget.field.value = 'non-existent-value';
fixture.detectChanges(); fixture.detectChanges();
@@ -682,7 +662,7 @@ describe('DropdownCloudWidgetComponent', () => {
expect(widget.fieldValue).toEqual(''); expect(widget.fieldValue).toEqual('');
}); });
it('should NOT reset the current value when it is part of the available options', () => { it('should not reset the current value when it is part of the available options', () => {
widget.field.options = mockConditionalEntries[1].options; widget.field.options = mockConditionalEntries[1].options;
widget.field.value = 'ATH'; widget.field.value = 'ATH';
fixture.detectChanges(); fixture.detectChanges();
@@ -714,10 +694,11 @@ describe('DropdownCloudWidgetComponent', () => {
describe('Load selection for linked dropdown (i.e. saved, completed forms)', () => { describe('Load selection for linked dropdown (i.e. saved, completed forms)', () => {
it('should load the selection of a manual type linked dropdown', () => { it('should load the selection of a manual type linked dropdown', () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'child-dropdown-id', id: 'child-dropdown-id',
name: 'child-dropdown', name: 'child-dropdown',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
optionType: 'manual', optionType: 'manual',
rule: { rule: {
ruleOn: 'parentDropdown', ruleOn: 'parentDropdown',
@@ -737,10 +718,11 @@ describe('DropdownCloudWidgetComponent', () => {
it('should load the selection of a rest type linked dropdown', () => { it('should load the selection of a rest type linked dropdown', () => {
const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(mockRestDropdownOptions)); const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(mockRestDropdownOptions));
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'child-dropdown-id', id: 'child-dropdown-id',
name: 'child-dropdown', name: 'child-dropdown',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
restUrl: 'mock-url.com/country=${country}', restUrl: 'mock-url.com/country=${country}',
optionType: 'rest', optionType: 'rest',
rule: { rule: {
@@ -762,10 +744,11 @@ describe('DropdownCloudWidgetComponent', () => {
describe('when form model has left labels', () => { describe('when form model has left labels', () => {
it('should have left labels classes on leftLabels true', async () => { it('should have left labels classes on leftLabels true', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, leftLabels: true }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'option list', name: 'option list',
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
readOnly: false,
options: filterOptionList options: filterOptionList
}); });
@@ -779,11 +762,12 @@ describe('DropdownCloudWidgetComponent', () => {
expect(adfLeftLabel).not.toBeNull(); expect(adfLeftLabel).not.toBeNull();
}); });
it('should NOT have left labels classes on leftLabels false', async () => { it('should not have left labels classes on leftLabels false', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, leftLabels: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: false }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'option list', name: 'option list',
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
readOnly: false,
options: filterOptionList options: filterOptionList
}); });
@@ -797,11 +781,12 @@ describe('DropdownCloudWidgetComponent', () => {
expect(adfLeftLabel).toBeNull(); expect(adfLeftLabel).toBeNull();
}); });
it('should NOT have left labels classes on leftLabels NOT present', async () => { it('should not have left labels classes on leftLabels not present', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false }), { widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id', id: 'dropdown-id',
name: 'option list', name: 'option list',
type: FormFieldTypes.DROPDOWN, type: FormFieldTypes.DROPDOWN,
readOnly: false,
options: filterOptionList options: filterOptionList
}); });
@@ -828,10 +813,11 @@ describe('DropdownCloudWidgetComponent', () => {
processVariables?: TaskVariableCloud[], processVariables?: TaskVariableCloud[],
variables?: TaskVariableCloud[] variables?: TaskVariableCloud[]
) => ) =>
new FormFieldModel(new FormModel({ taskId: 'fake-task-id', readOnly: false, processVariables, variables }), { new FormFieldModel(new FormModel({ taskId: 'fake-task-id', processVariables, variables }), {
id: 'variable-dropdown-id', id: 'variable-dropdown-id',
name: 'variable-options-dropdown', name: 'variable-options-dropdown',
type: 'dropdown', type: 'dropdown',
readOnly: 'false',
optionType: 'variable', optionType: 'variable',
variableConfig: { variableConfig: {
variableName, variableName,
@@ -975,20 +961,5 @@ describe('DropdownCloudWidgetComponent', () => {
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message')); const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
expect(failedErrorMsgElement).toBeNull(); expect(failedErrorMsgElement).toBeNull();
}); });
it('should NOT display errors if field is readonly', () => {
widget.field = getVariableDropdownWidget(
'variables.wrong-variable-id',
'response.wrongPath.players',
'wrongId',
'wrongFullName',
mockProcessVariablesWithJson
);
widget.field.readOnly = true;
fixture.detectChanges();
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
expect(failedErrorMsgElement).toBeNull();
});
}); });
}); });

View File

@@ -191,28 +191,26 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
} }
private persistFieldOptionsFromRestApi() { private persistFieldOptionsFromRestApi() {
if (!this.isValidRestType() || this.field.readOnly) { if (this.isValidRestType()) {
return; this.resetRestApiErrorMessage();
const bodyParam = this.buildBodyParam();
this.formCloudService
.getRestWidgetData(this.field.form.id, this.field.id, bodyParam)
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(result: FormFieldOption[]) => {
this.resetRestApiErrorMessage();
this.field.options = result;
this.updateOptions();
this.field.updateForm();
this.resetInvalidValue();
},
(err) => {
this.resetRestApiOptions();
this.handleError(err);
}
);
} }
this.resetRestApiErrorMessage();
const bodyParam = this.buildBodyParam();
this.formCloudService
.getRestWidgetData(this.field.form.id, this.field.id, bodyParam)
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(result: FormFieldOption[]) => {
this.resetRestApiErrorMessage();
this.field.options = result;
this.updateOptions();
this.field.updateForm();
this.resetInvalidValue();
},
(err) => {
this.resetRestApiOptions();
this.handleError(err);
}
);
} }
private buildBodyParam(): any { private buildBodyParam(): any {