diff --git a/lib/core/i18n/en.json b/lib/core/i18n/en.json
index 3617ef42b2..6798f8606b 100644
--- a/lib/core/i18n/en.json
+++ b/lib/core/i18n/en.json
@@ -42,6 +42,7 @@
"REMOVE_FILE": "Remove",
"UPLOAD": "UPLOAD",
"REQUIRED": "*Required",
+ "REST_API_FAILED": "The server `{{ hostname }}` is not reachable",
"FILE_NAME": "File Name",
"NO_FILE_ATTACHED": "No file attached",
"VALIDATOR": {
diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.html b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.html
index 35a78ae2a2..7b04b5666e 100644
--- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.html
+++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.html
@@ -29,4 +29,6 @@
+
diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.scss b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.scss
index e770d674b6..9a675ba27a 100644
--- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.scss
+++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.scss
@@ -19,5 +19,9 @@
&-dropdown-required-message .adf-error-text-container {
margin-top: 1px !important;
}
+
+ &-dropdown-failed-message .adf-error-text-container {
+ margin-top: 1px !important;
+ }
}
}
diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts
index aed7b27ddf..408d8411ec 100644
--- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts
+++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts
@@ -17,7 +17,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
-import { of } from 'rxjs';
+import { of, throwError } from 'rxjs';
import { DropdownCloudWidgetComponent } from './dropdown-cloud.widget';
import { FormFieldModel, FormModel, FormService, setupTestBed } from '@alfresco/adf-core';
import { FormCloudService } from '../../../services/form-cloud.service';
@@ -27,7 +27,8 @@ import {
fakeOptionList,
filterOptionList,
mockConditionalEntries,
- mockRestDropdownOptions
+ mockRestDropdownOptions,
+ mockSecondRestDropdownOptions
} from '../../../mocks/dropdown.mock';
import { OverlayContainer } from '@angular/cdk/overlay';
@@ -78,7 +79,7 @@ describe('DropdownCloudWidgetComponent', () => {
name: 'date-name',
type: 'dropdown',
readOnly: false,
- restUrl: 'fake-rest-url'
+ restUrl: 'https://fake-rest-url'
});
widget.field.emptyOption = { id: 'empty', name: 'Choose one...' };
widget.field.isVisible = true;
@@ -134,7 +135,7 @@ describe('DropdownCloudWidgetComponent', () => {
it('should load data from restUrl and populate options', async () => {
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.restIdProperty = 'name';
@@ -159,8 +160,30 @@ describe('DropdownCloudWidgetComponent', () => {
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 () => {
- widget.field.restUrl = 'fake-rest-url';
+ widget.field.restUrl = 'https://fake-rest-url';
widget.field.optionType = 'rest';
widget.field.value = {
id: 'opt1',
@@ -188,7 +211,7 @@ describe('DropdownCloudWidgetComponent', () => {
});
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.value = 'opt1';
@@ -367,6 +390,44 @@ describe('DropdownCloudWidgetComponent', () => {
expect(optTwo.context.value).toBe('MA');
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', () => {
diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts
index 6dd75aa277..d28b7c4ac5 100644
--- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts
+++ b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.ts
@@ -59,6 +59,8 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
typeId = 'DropdownCloudWidgetComponent';
HIDE_FILTER_LIMIT = 5;
showInputFilter = false;
+ isRestApiFailed = false;
+ restApiHostName: string;
list$: Observable;
filter$ = new BehaviorSubject('');
@@ -93,14 +95,19 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
private persistFieldOptionsFromRestApi() {
if (this.isValidRestType()) {
+ 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();
- }, (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)) {
this.isValidRestType() ? this.persistFieldOptionsFromRestApi() : this.persistFieldOptionsFromManualList(value);
} else if (this.isDefaultValue(value)) {
+ this.resetRestApiErrorMessage();
this.addDefaultOption();
}
}
@@ -253,4 +261,25 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
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;
+ }
+ }
}
diff --git a/lib/process-services-cloud/src/lib/form/mocks/dropdown.mock.ts b/lib/process-services-cloud/src/lib/form/mocks/dropdown.mock.ts
index 38b2ab2c2b..9cb69c0917 100644
--- a/lib/process-services-cloud/src/lib/form/mocks/dropdown.mock.ts
+++ b/lib/process-services-cloud/src/lib/form/mocks/dropdown.mock.ts
@@ -84,6 +84,11 @@ export const mockRestDropdownOptions: FormFieldOption[] = [
{ id: 'MA', name: 'MANCHESTER' }
];
+export const mockSecondRestDropdownOptions: FormFieldOption[] = [
+ { id: 'MI', name: 'MILAN' },
+ { id: 'RM', name: 'ROME' }
+];
+
export const fakeOptionList: FormFieldOption[] = [
{ id: 'opt_1', name: 'option_1' },
{ id: 'opt_2', name: 'option_2' },