mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-6660] FE - [ADF] Linked dropdown still contains old options when the rest api does not return results (#7454)
* [AAE-6660] FE - [ADF] Linked dropdown still contains old options when the rest api does not return results * * Added unit tests to the recent changes done on dropdown. * * Improved error message * My empty commit to kick start travis * * Fixed lint errors * * Fixed css lint error * * Fixed failing unit test
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
"REMOVE_FILE": "Remove",
|
"REMOVE_FILE": "Remove",
|
||||||
"UPLOAD": "UPLOAD",
|
"UPLOAD": "UPLOAD",
|
||||||
"REQUIRED": "*Required",
|
"REQUIRED": "*Required",
|
||||||
|
"REST_API_FAILED": "The server `{{ hostname }}` is not reachable",
|
||||||
"FILE_NAME": "File Name",
|
"FILE_NAME": "File Name",
|
||||||
"NO_FILE_ATTACHED": "No file attached",
|
"NO_FILE_ATTACHED": "No file attached",
|
||||||
"VALIDATOR": {
|
"VALIDATOR": {
|
||||||
|
@@ -29,4 +29,6 @@
|
|||||||
<error-widget [error]="field.validationSummary"></error-widget>
|
<error-widget [error]="field.validationSummary"></error-widget>
|
||||||
<error-widget class="adf-dropdown-required-message" *ngIf="isInvalidFieldRequired()"
|
<error-widget class="adf-dropdown-required-message" *ngIf="isInvalidFieldRequired()"
|
||||||
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
|
required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
|
||||||
|
<error-widget class="adf-dropdown-failed-message" *ngIf="isRestApiFailed"
|
||||||
|
required="{{ 'FORM.FIELD.REST_API_FAILED' | translate: { hostname: restApiHostName } }}"></error-widget>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -19,5 +19,9 @@
|
|||||||
&-dropdown-required-message .adf-error-text-container {
|
&-dropdown-required-message .adf-error-text-container {
|
||||||
margin-top: 1px !important;
|
margin-top: 1px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-dropdown-failed-message .adf-error-text-container {
|
||||||
|
margin-top: 1px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { of } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { DropdownCloudWidgetComponent } from './dropdown-cloud.widget';
|
import { DropdownCloudWidgetComponent } from './dropdown-cloud.widget';
|
||||||
import { FormFieldModel, FormModel, FormService, setupTestBed } from '@alfresco/adf-core';
|
import { FormFieldModel, FormModel, FormService, setupTestBed } from '@alfresco/adf-core';
|
||||||
import { FormCloudService } from '../../../services/form-cloud.service';
|
import { FormCloudService } from '../../../services/form-cloud.service';
|
||||||
@@ -27,7 +27,8 @@ import {
|
|||||||
fakeOptionList,
|
fakeOptionList,
|
||||||
filterOptionList,
|
filterOptionList,
|
||||||
mockConditionalEntries,
|
mockConditionalEntries,
|
||||||
mockRestDropdownOptions
|
mockRestDropdownOptions,
|
||||||
|
mockSecondRestDropdownOptions
|
||||||
} from '../../../mocks/dropdown.mock';
|
} from '../../../mocks/dropdown.mock';
|
||||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
name: 'date-name',
|
name: 'date-name',
|
||||||
type: 'dropdown',
|
type: 'dropdown',
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
restUrl: 'fake-rest-url'
|
restUrl: 'https://fake-rest-url'
|
||||||
});
|
});
|
||||||
widget.field.emptyOption = { id: 'empty', name: 'Choose one...' };
|
widget.field.emptyOption = { id: 'empty', name: 'Choose one...' };
|
||||||
widget.field.isVisible = true;
|
widget.field.isVisible = true;
|
||||||
@@ -134,7 +135,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
|
|
||||||
it('should load data from restUrl and populate options', async () => {
|
it('should load data from restUrl and populate options', async () => {
|
||||||
const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(fakeOptionList));
|
const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(fakeOptionList));
|
||||||
widget.field.restUrl = 'fake-rest-url';
|
widget.field.restUrl = 'https://fake-rest-url';
|
||||||
widget.field.optionType = 'rest';
|
widget.field.optionType = 'rest';
|
||||||
widget.field.restIdProperty = 'name';
|
widget.field.restIdProperty = 'name';
|
||||||
|
|
||||||
@@ -159,8 +160,30 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
expect(optThree.nativeElement.innerText).toEqual('option_3');
|
expect(optThree.nativeElement.innerText).toEqual('option_3');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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'));
|
||||||
|
widget.field.restUrl = 'https://fake-rest-url';
|
||||||
|
widget.field.optionType = 'rest';
|
||||||
|
widget.field.restIdProperty = 'name';
|
||||||
|
|
||||||
|
widget.ngOnInit();
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const dropdown = fixture.debugElement.query(By.css('mat-select'));
|
||||||
|
dropdown.nativeElement.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
|
||||||
|
|
||||||
|
expect(jsonDataSpy).toHaveBeenCalled();
|
||||||
|
expect(widget.isRestApiFailed).toBe(true);
|
||||||
|
expect(widget.field.options.length).toEqual(0);
|
||||||
|
expect(failedErrorMsgElement.nativeElement.innerText.trim()).toBe('FORM.FIELD.REST_API_FAILED');
|
||||||
|
});
|
||||||
|
|
||||||
it('should preselect dropdown widget value when Json (rest call) passed', async () => {
|
it('should preselect dropdown widget value when Json (rest call) passed', async () => {
|
||||||
widget.field.restUrl = 'fake-rest-url';
|
widget.field.restUrl = 'https://fake-rest-url';
|
||||||
widget.field.optionType = 'rest';
|
widget.field.optionType = 'rest';
|
||||||
widget.field.value = {
|
widget.field.value = {
|
||||||
id: 'opt1',
|
id: 'opt1',
|
||||||
@@ -188,7 +211,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should preselect dropdown widget value when String (defined value) passed ', async () => {
|
it('should preselect dropdown widget value when String (defined value) passed ', async () => {
|
||||||
widget.field.restUrl = 'fake-rest-url';
|
widget.field.restUrl = 'https://fake-rest-url';
|
||||||
widget.field.optionType = 'rest';
|
widget.field.optionType = 'rest';
|
||||||
widget.field.value = 'opt1';
|
widget.field.value = 'opt1';
|
||||||
|
|
||||||
@@ -367,6 +390,44 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
expect(optTwo.context.value).toBe('MA');
|
expect(optTwo.context.value).toBe('MA');
|
||||||
expect(optTwo.context.viewValue).toBe('MANCHESTER');
|
expect(optTwo.context.viewValue).toBe('MANCHESTER');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should reset previous child options if the rest url failed for a linked dropdown', async () => {
|
||||||
|
const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(mockRestDropdownOptions));
|
||||||
|
const mockParentDropdown = { id: 'parentDropdown', value: 'mock-value', validate: () => true };
|
||||||
|
spyOn(widget.field.form, 'getFormFields').and.returnValue([mockParentDropdown]);
|
||||||
|
|
||||||
|
function selectParentOption(parentOptionName: string) {
|
||||||
|
parentDropdown.value = parentOptionName;
|
||||||
|
widget.selectionChangedForField(parentDropdown);
|
||||||
|
fixture.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectParentOption('UK');
|
||||||
|
await openSelect('child-dropdown-id');
|
||||||
|
const failedErrorMsgElement1 = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
|
||||||
|
|
||||||
|
expect(widget.isRestApiFailed).toBe(false);
|
||||||
|
expect(widget.field.options.length).toBe(2);
|
||||||
|
expect(failedErrorMsgElement1).toBeNull();
|
||||||
|
|
||||||
|
jsonDataSpy.and.returnValue(throwError('Failed to fetch options'));
|
||||||
|
selectParentOption('GR');
|
||||||
|
await openSelect('child-dropdown-id');
|
||||||
|
const failedErrorMsgElement2 = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
|
||||||
|
|
||||||
|
expect(widget.isRestApiFailed).toBe(true);
|
||||||
|
expect(widget.field.options.length).toBe(0);
|
||||||
|
expect(failedErrorMsgElement2.nativeElement.innerText.trim()).toBe('FORM.FIELD.REST_API_FAILED');
|
||||||
|
|
||||||
|
jsonDataSpy.and.returnValue(of(mockSecondRestDropdownOptions));
|
||||||
|
selectParentOption('IT');
|
||||||
|
await openSelect('child-dropdown-id');
|
||||||
|
const failedErrorMsgElement3 = fixture.debugElement.query(By.css('.adf-dropdown-failed-message'));
|
||||||
|
|
||||||
|
expect(widget.isRestApiFailed).toBe(false);
|
||||||
|
expect(widget.field.options.length).toBe(2);
|
||||||
|
expect(failedErrorMsgElement3).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Manual options', () => {
|
describe('Manual options', () => {
|
||||||
|
@@ -59,6 +59,8 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
typeId = 'DropdownCloudWidgetComponent';
|
typeId = 'DropdownCloudWidgetComponent';
|
||||||
HIDE_FILTER_LIMIT = 5;
|
HIDE_FILTER_LIMIT = 5;
|
||||||
showInputFilter = false;
|
showInputFilter = false;
|
||||||
|
isRestApiFailed = false;
|
||||||
|
restApiHostName: string;
|
||||||
list$: Observable<FormFieldOption[]>;
|
list$: Observable<FormFieldOption[]>;
|
||||||
filter$ = new BehaviorSubject<string>('');
|
filter$ = new BehaviorSubject<string>('');
|
||||||
|
|
||||||
@@ -93,14 +95,19 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
|
|
||||||
private persistFieldOptionsFromRestApi() {
|
private persistFieldOptionsFromRestApi() {
|
||||||
if (this.isValidRestType()) {
|
if (this.isValidRestType()) {
|
||||||
|
this.resetRestApiErrorMessage();
|
||||||
const bodyParam = this.buildBodyParam();
|
const bodyParam = this.buildBodyParam();
|
||||||
this.formCloudService.getRestWidgetData(this.field.form.id, this.field.id, bodyParam)
|
this.formCloudService.getRestWidgetData(this.field.form.id, this.field.id, bodyParam)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe((result: FormFieldOption[]) => {
|
.subscribe((result: FormFieldOption[]) => {
|
||||||
|
this.resetRestApiErrorMessage();
|
||||||
this.field.options = result;
|
this.field.options = result;
|
||||||
this.updateOptions();
|
this.updateOptions();
|
||||||
this.field.updateForm();
|
this.field.updateForm();
|
||||||
}, (err) => this.handleError(err));
|
}, (err) => {
|
||||||
|
this.resetRestApiOptions();
|
||||||
|
this.handleError(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +136,7 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
if (this.isValidValue(value)) {
|
if (this.isValidValue(value)) {
|
||||||
this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value);
|
this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value);
|
||||||
} else if (this.isDefaultValue(value)) {
|
} else if (this.isDefaultValue(value)) {
|
||||||
|
this.resetRestApiErrorMessage();
|
||||||
this.addDefaultOption();
|
this.addDefaultOption();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,4 +261,25 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
takeUntil(this.onDestroy$)
|
takeUntil(this.onDestroy$)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetRestApiErrorMessage() {
|
||||||
|
this.isRestApiFailed = false;
|
||||||
|
this.restApiHostName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
resetRestApiOptions() {
|
||||||
|
this.field.options = [];
|
||||||
|
this.isRestApiFailed = true;
|
||||||
|
this.restApiHostName = this.getRestUrlHostName();
|
||||||
|
this.updateOptions();
|
||||||
|
this.field.updateForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRestUrlHostName(): string {
|
||||||
|
try {
|
||||||
|
return new URL(this.field?.restUrl).hostname;
|
||||||
|
} catch {
|
||||||
|
return this.field?.restUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -84,6 +84,11 @@ export const mockRestDropdownOptions: FormFieldOption[] = [
|
|||||||
{ id: 'MA', name: 'MANCHESTER' }
|
{ id: 'MA', name: 'MANCHESTER' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const mockSecondRestDropdownOptions: FormFieldOption[] = [
|
||||||
|
{ id: 'MI', name: 'MILAN' },
|
||||||
|
{ id: 'RM', name: 'ROME' }
|
||||||
|
];
|
||||||
|
|
||||||
export const fakeOptionList: FormFieldOption[] = [
|
export const fakeOptionList: FormFieldOption[] = [
|
||||||
{ id: 'opt_1', name: 'option_1' },
|
{ id: 'opt_1', name: 'option_1' },
|
||||||
{ id: 'opt_2', name: 'option_2' },
|
{ id: 'opt_2', name: 'option_2' },
|
||||||
|
Reference in New Issue
Block a user