diff --git a/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.html b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.html
new file mode 100644
index 0000000000..fa2d9eb593
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.html
@@ -0,0 +1,20 @@
+
+
+
+
+ {{opt.name}}
+
+ {{field.value}}
+
+
+
+
+
diff --git a/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.scss b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.scss
new file mode 100644
index 0000000000..8e397e6e53
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.scss
@@ -0,0 +1,25 @@
+.adf {
+ &-dropdown-widget {
+ width: 100%;
+ margin-top: 13px;
+
+ .adf-select {
+ padding-top: 0 !important;
+ width: 100%;
+ }
+
+ .mat-select-value-text {
+ font-size: 14px;
+ }
+
+ &-select {
+ width: 100%;
+ }
+
+ &-dropdown-required-message .adf-error-text-container {
+ margin-top: 1px !important;
+ }
+
+ }
+
+}
diff --git a/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.spec.ts
new file mode 100644
index 0000000000..92203fa610
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.spec.ts
@@ -0,0 +1,191 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { of } from 'rxjs';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { DropdownCloudWidgetComponent } from './dropdown-cloud.widget';
+import { FormService, WidgetVisibilityService, FormFieldOption, setupTestBed, FormFieldModel, FormModel, CoreModule } from '@alfresco/adf-core';
+import { FormCloudService } from '../../services/form-cloud.service';
+
+describe('DropdownCloudWidgetComponent', () => {
+
+ let formService: FormService;
+ let widget: DropdownCloudWidgetComponent;
+ let visibilityService: WidgetVisibilityService;
+ let formCloudService: FormCloudService;
+ let fixture: ComponentFixture;
+ let element: HTMLElement;
+
+ function openSelect() {
+ const dropdown = fixture.debugElement.query(By.css('[class="mat-select-trigger"]'));
+ dropdown.triggerEventHandler('click', null);
+ fixture.detectChanges();
+ }
+
+ const fakeOptionList: FormFieldOption[] = [
+ { id: 'opt_1', name: 'option_1' },
+ { id: 'opt_2', name: 'option_2' },
+ { id: 'opt_3', name: 'option_3' }];
+
+ setupTestBed({
+ imports: [
+ NoopAnimationsModule,
+ CoreModule.forRoot()
+ ],
+ declarations: [DropdownCloudWidgetComponent],
+ providers: [FormCloudService]
+ });
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(DropdownCloudWidgetComponent);
+ widget = fixture.componentInstance;
+ element = fixture.nativeElement;
+ formService = TestBed.get(FormService);
+ visibilityService = TestBed.get(WidgetVisibilityService);
+ formCloudService = TestBed.get(FormCloudService);
+
+ widget.field = new FormFieldModel(new FormModel());
+ }));
+
+ it('should require field with restUrl', async(() => {
+ spyOn(formService, 'getRestFieldValues').and.stub();
+
+ widget.field = null;
+ widget.ngOnInit();
+ expect(formService.getRestFieldValues).not.toHaveBeenCalled();
+
+ widget.field = new FormFieldModel(null, { restUrl: null });
+ widget.ngOnInit();
+ expect(formService.getRestFieldValues).not.toHaveBeenCalled();
+ }));
+
+ describe('when template is ready', () => {
+
+ describe('and dropdown is populated', () => {
+
+ beforeEach(async(() => {
+ spyOn(visibilityService, 'refreshVisibility').and.stub();
+ spyOn(formService, 'getRestFieldValues').and.callFake(() => {
+ return of(fakeOptionList);
+ });
+ widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
+ id: 'dropdown-id',
+ name: 'date-name',
+ type: 'dropdown',
+ readOnly: 'false',
+ restUrl: 'fake-rest-url'
+ });
+ widget.field.emptyOption = { id: 'empty', name: 'Choose one...' };
+ widget.field.isVisible = true;
+ fixture.detectChanges();
+ }));
+
+ it('should show visible dropdown widget', async(() => {
+ expect(element.querySelector('#dropdown-id')).toBeDefined();
+ expect(element.querySelector('#dropdown-id')).not.toBeNull();
+
+ openSelect();
+
+ const optOne = fixture.debugElement.queryAll(By.css('[id="mat-option-1"]'));
+ const optTwo = fixture.debugElement.queryAll(By.css('[id="mat-option-2"]'));
+ const optThree = fixture.debugElement.queryAll(By.css('[id="mat-option-3"]'));
+
+ expect(optOne).not.toBeNull();
+ expect(optTwo).not.toBeNull();
+ expect(optThree).not.toBeNull();
+ }));
+
+ it('should select the default value when an option is chosen as default', async(() => {
+ widget.field.value = 'option_2';
+ widget.ngOnInit();
+ fixture.detectChanges();
+ fixture.whenStable()
+ .then(() => {
+ const dropDownElement: any = element.querySelector('#dropdown-id');
+ expect(dropDownElement.attributes['ng-reflect-model'].value).toBe('option_2');
+ expect(dropDownElement.attributes['ng-reflect-model'].textContent).toBe('option_2');
+ });
+ }));
+
+ it('should select the empty value when no default is chosen', async(() => {
+ widget.field.value = 'empty';
+ widget.ngOnInit();
+ fixture.detectChanges();
+
+ openSelect();
+
+ fixture.detectChanges();
+
+ fixture.whenStable()
+ .then(() => {
+ const dropDownElement: any = element.querySelector('#dropdown-id');
+ expect(dropDownElement.attributes['ng-reflect-model'].value).toBe('empty');
+ });
+ }));
+
+ it('should load data from restUrl and populate options', async(() => {
+ widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
+ id: 'dropdown-id',
+ name: 'date-name',
+ type: 'dropdown-cloud',
+ readOnly: 'true',
+ restUrl: 'fake-rest-url',
+ optionType: 'rest',
+ restIdProperty: 'name'
+ });
+ const jsonDataSpy = spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of(fakeOptionList));
+ const optOne = fixture.debugElement.queryAll(By.css('[id="mat-option-1"]'));
+ widget.ngOnInit();
+ fixture.detectChanges();
+ fixture.whenStable().then(() => {
+ expect(jsonDataSpy).toHaveBeenCalled();
+ expect(optOne).not.toBeNull();
+ });
+ }));
+
+ it('shoud map properties if restResponsePath is set', async(() => {
+ widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
+ id: 'dropdown-id',
+ name: 'date-name',
+ type: 'dropdown-cloud',
+ readOnly: 'true',
+ restUrl: 'fake-rest-url',
+ optionType: 'rest',
+ restResponsePath: 'path',
+ restIdProperty: 'name'
+ });
+
+ spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of([{
+ id: 1,
+ path: {
+ name: 'test1'
+ }
+ }]));
+ spyOn(widget, 'mapJsonData').and.returnValue([]);
+
+ widget.ngOnInit();
+ fixture.detectChanges();
+ fixture.whenStable().then(() => {
+ expect(widget.mapJsonData).toHaveBeenCalled();
+ });
+ }));
+
+ });
+ });
+});
diff --git a/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.ts
new file mode 100644
index 0000000000..7058a13ee2
--- /dev/null
+++ b/lib/process-services-cloud/src/lib/form/components/dropdown-cloud/dropdown-cloud.widget.ts
@@ -0,0 +1,92 @@
+/*!
+ * @license
+ * Copyright 2019 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+import { baseHost, WidgetComponent, FormService, LogService, FormFieldOption } from '@alfresco/adf-core';
+import { FormCloudService } from '../../services/form-cloud.service';
+
+ /* tslint:disable:component-selector */
+
+@Component({
+ selector: 'dropdown-cloud-widget',
+ templateUrl: './dropdown-cloud.widget.html',
+ styleUrls: ['./dropdown-cloud.widget.scss'],
+ host: baseHost,
+ encapsulation: ViewEncapsulation.None
+})
+export class DropdownCloudWidgetComponent extends WidgetComponent implements OnInit {
+
+ constructor(public formService: FormService,
+ private formCloudService: FormCloudService,
+ private logService: LogService) {
+ super(formService);
+ }
+
+ ngOnInit() {
+ if (this.field && this.field.restUrl) {
+ this.getValuesFromRestApi();
+ }
+ }
+
+ getValuesFromRestApi() {
+ if (this.isValidRestType()) {
+ this.formCloudService.getDropDownJsonData(this.field.restUrl).subscribe( (result: FormFieldOption[]) => {
+ if (this.field.restResponsePath) {
+ this.field.options = this.mapJsonData(result);
+ } else {
+ this.field.options = result;
+ }
+ },
+ (err) => this.handleError(err));
+ }
+ }
+
+ mapJsonData(data: any[]): FormFieldOption[] {
+ const path = this.field.restResponsePath;
+ const idProperty = this.field.restIdProperty;
+
+ return data.map( (value: any) => {
+ return {
+ name: value[path][idProperty],
+ id: value.id
+ };
+ });
+ }
+
+ getOptionValue(option: FormFieldOption, fieldValue: string): string {
+ let optionValue: string = '';
+ if (option.id === 'empty' || option.name !== fieldValue) {
+ optionValue = option.id;
+ } else {
+ optionValue = option.name;
+ }
+ return optionValue;
+ }
+
+ isValidRestType(): boolean {
+ return this.field.optionType === 'rest' && !!this.field.restUrl;
+ }
+
+ handleError(error: any) {
+ this.logService.error(error);
+ }
+
+ isReadOnlyType(): boolean {
+ return this.field.type === 'readonly' ? true : false;
+ }
+
+ }
diff --git a/lib/process-services-cloud/src/lib/form/form-cloud.module.ts b/lib/process-services-cloud/src/lib/form/form-cloud.module.ts
index 19c21a898c..7d843b6485 100644
--- a/lib/process-services-cloud/src/lib/form/form-cloud.module.ts
+++ b/lib/process-services-cloud/src/lib/form/form-cloud.module.ts
@@ -26,6 +26,7 @@ import { FormCloudComponent } from './components/form-cloud.component';
import { FormDefinitionSelectorCloudComponent } from './components/form-definition-selector-cloud.component';
import { FormDefinitionSelectorCloudService } from './services/form-definition-selector-cloud.service';
import { FormCustomOutcomesComponent } from './components/form-cloud-custom-outcomes.component';
+import { DropdownCloudWidgetComponent } from './components/dropdown-cloud/dropdown-cloud.widget';
@NgModule({
imports: [
@@ -39,10 +40,13 @@ import { FormCustomOutcomesComponent } from './components/form-cloud-custom-outc
FormBaseModule,
CoreModule
],
- declarations: [FormCloudComponent, UploadCloudWidgetComponent, FormDefinitionSelectorCloudComponent, FormCustomOutcomesComponent],
- providers: [FormDefinitionSelectorCloudService],
+ declarations: [FormCloudComponent, UploadCloudWidgetComponent, FormDefinitionSelectorCloudComponent, FormCustomOutcomesComponent, DropdownCloudWidgetComponent],
+ providers: [
+ FormDefinitionSelectorCloudService
+ ],
entryComponents: [
- UploadCloudWidgetComponent
+ UploadCloudWidgetComponent,
+ DropdownCloudWidgetComponent
],
exports: [
FormCloudComponent, UploadCloudWidgetComponent, FormDefinitionSelectorCloudComponent, FormCustomOutcomesComponent
diff --git a/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts b/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts
index c6e2c04466..6172757f79 100644
--- a/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts
+++ b/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts
@@ -16,7 +16,7 @@
*/
import { Injectable } from '@angular/core';
-import { AlfrescoApiService, LogService, FormValues, AppConfigService, FormOutcomeModel } from '@alfresco/adf-core';
+import { AlfrescoApiService, LogService, FormValues, AppConfigService, FormOutcomeModel, FormFieldOption } from '@alfresco/adf-core';
import { throwError, Observable, from } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { TaskDetailsCloudModel } from '../../task/start-task/models/task-details-cloud.model';
@@ -224,6 +224,26 @@ export class FormCloudService extends BaseCloudService {
);
}
+ /**
+ * Parses JSON data to create a corresponding form.
+ * @param url String data to make the request
+ * @returns Array of FormFieldOption object
+ */
+ getDropDownJsonData(url: string): Observable {
+ return from(this.apiService.getInstance()
+ .oauth2Auth.callCustomApi(url, 'GET',
+ null, null, null,
+ null, null,
+ this.contentTypes, this.accepts,
+ this.returnType, null, null)
+ ).pipe(
+ map((res: any) => {
+ return res;
+ }),
+ catchError((err) => this.handleError(err))
+ );
+ }
+
/**
* Parses JSON data to create a corresponding form.
* @param json JSON data to create the form
diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts
index 5ecac0805d..fd5619cc2e 100644
--- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts
+++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts
@@ -24,6 +24,7 @@ import { TaskDetailsCloudModel } from '../../start-task/models/task-details-clou
import { TaskCloudService } from '../../services/task-cloud.service';
import { FormRenderingService } from '@alfresco/adf-core';
import { UploadCloudWidgetComponent } from '../../../form/components/upload-cloud.widget';
+import { DropdownCloudWidgetComponent } from '../../../form/components/dropdown-cloud/dropdown-cloud.widget';
@Component({
selector: 'adf-cloud-task-form',
@@ -94,6 +95,7 @@ export class TaskFormCloudComponent implements OnChanges {
private taskCloudService: TaskCloudService,
private formRenderingService: FormRenderingService) {
this.formRenderingService.setComponentTypeResolver('upload', () => UploadCloudWidgetComponent, true);
+ this.formRenderingService.setComponentTypeResolver('dropdown', () => DropdownCloudWidgetComponent, true);
}
ngOnChanges(changes: SimpleChanges) {