Skip to content

Commit

Permalink
[AAE-6093] - fixed rest option for cloud widget (#7304)
Browse files Browse the repository at this point in the history
* [AAE-6093] - fixed rest option for cloud widget

* [AAE-6093] - reverted app config change

* [AAE-6093] - fixed naming

* [AAE-6093] - fixed radio button complete task and added support for rest url with the new feature

* [AAE-6093] - removed test value

* [AAE-6093] - fixed lint

* [AAE-6093] - fixed lint

* [AAE-6093] - merged fix for dropdown
  • Loading branch information
VitoAlbano committed Oct 29, 2021
1 parent c596a06 commit 7481001
Show file tree
Hide file tree
Showing 12 changed files with 431 additions and 129 deletions.
92 changes: 92 additions & 0 deletions lib/core/form/components/widgets/core/form-field.model.spec.ts
Expand Up @@ -691,6 +691,98 @@ describe('FormFieldModel', () => {
expect(form.values['dropdown_field'].name).toEqual('Option 1');
});

it('dropdown field type should be formatted on rest properties', () => {
const form = new FormModel();
const field = new FormFieldModel(form, {
fieldType: 'HeaderFieldtype',
id: 'dropdown_field',
name: 'header',
type: FormFieldTypes.DROPDOWN,
value: 'opt1',
required: false,
readOnly: true,
restUrl: 'fake-url-just-to-show',
optionType: 'rest',
restIdProperty: 'fake-id-property',
restLabelProperty: 'fake-label-property',
options: [
{id: 'opt1', name: 'Option 1'},
{id: 'opt2', name: 'Option 2'}
]
});
field.updateForm();
expect(form.values['dropdown_field']['fake-id-property']).toEqual('opt1');
expect(form.values['dropdown_field']['fake-label-property']).toEqual('Option 1');
});

it('dropdown field type should be formatted on id and name properties if rest properties are not set', () => {
const form = new FormModel();
const field = new FormFieldModel(form, {
fieldType: 'HeaderFieldtype',
id: 'dropdown_field',
name: 'header',
type: FormFieldTypes.DROPDOWN,
value: 'opt1',
required: false,
readOnly: true,
restUrl: 'fake-url-just-to-show',
optionType: 'rest',
options: [
{id: 'opt1', name: 'Option 1'},
{id: 'opt2', name: 'Option 2'}
]
});
field.updateForm();
expect(form.values['dropdown_field']['id']).toEqual('opt1');
expect(form.values['dropdown_field']['name']).toEqual('Option 1');
});

it('radio button field rest type should appear with its configured label and id into the rest values', () => {
const form = new FormModel();
const field = new FormFieldModel(form, {
fieldType: 'HeaderFieldtype',
id: 'radio_bananan_field',
name: 'banana',
type: FormFieldTypes.RADIO_BUTTONS,
value: 'opt1',
required: false,
readOnly: true,
restUrl: '<whatever-url-you-like-we-do-not-mind>',
restIdProperty: 'banana',
restLabelProperty: 'banLabel',
optionType: 'rest',
options: [
{id: 'opt1', name: 'Option 1'},
{id: 'opt2', name: 'Option 2'}
]
});
field.updateForm();
expect(form.values['radio_bananan_field']['banana']).toEqual('opt1');
expect(form.values['radio_bananan_field']['banLabel']).toEqual('Option 1');
});

it('radio button field rest type should appear with id / name properties when rest properties are not configured', () => {
const form = new FormModel();
const field = new FormFieldModel(form, {
fieldType: 'HeaderFieldtype',
id: 'radio_bananan_field',
name: 'banana',
type: FormFieldTypes.RADIO_BUTTONS,
value: 'opt1',
required: false,
readOnly: true,
restUrl: '<whatever-url-you-like-we-do-not-mind>',
optionType: 'rest',
options: [
{id: 'opt1', name: 'Option 1'},
{id: 'opt2', name: 'Option 2'}
]
});
field.updateForm();
expect(form.values['radio_bananan_field']['id']).toEqual('opt1');
expect(form.values['radio_bananan_field']['name']).toEqual('Option 1');
});

it('should parse and resolve people null value as null', () => {
const field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.PEOPLE,
Expand Down
23 changes: 16 additions & 7 deletions lib/core/form/components/widgets/core/form-field.model.ts
Expand Up @@ -62,7 +62,7 @@ export class FormFieldModel extends FormWidgetModel {
restLabelProperty: string;
hasEmptyValue: boolean;
className: string;
optionType: string;
optionType: 'rest' | 'manual' ;
params: FormFieldMetadata = {};
hyperlinkUrl: string;
displayText: string;
Expand Down Expand Up @@ -372,18 +372,14 @@ export class FormFieldModel extends FormWidgetModel {

const entry: FormFieldOption[] = this.options.filter((opt) => opt.id === this.value);
if (entry.length > 0) {
this.form.values[this.id] = entry[0];
this.setFormFieldValueOption(entry[0]);
}
}
break;
case FormFieldTypes.RADIO_BUTTONS:
/*
This is needed due to Activiti issue related to reading radio button values as value string
but saving back as object: { id: <id>, name: <name> }
*/
const radioButton: FormFieldOption[] = this.options.filter((opt) => opt.id === this.value);
if (radioButton.length > 0) {
this.form.values[this.id] = radioButton[0];
this.setFormFieldValueOption(radioButton[0]);
}
break;
case FormFieldTypes.UPLOAD:
Expand Down Expand Up @@ -491,4 +487,17 @@ export class FormFieldModel extends FormWidgetModel {
json.type === FormFieldTypes.BOOLEAN;
}

private setFormFieldValueOption(option: FormFieldOption ) {
if (this.optionType === 'rest' && !!this.restUrl) {
const restEntry = {};
const restIdProperty = this.restIdProperty || 'id';
const restLabelProperty = this.restLabelProperty || 'name';
restEntry[restIdProperty] = option.id;
restEntry[restLabelProperty] = option.name;
this.form.values[this.id] = restEntry;
} else {
this.form.values[this.id] = option;
}
}

}
Expand Up @@ -23,6 +23,7 @@ import { DateCloudWidgetComponent } from './widgets/date/date-cloud.widget';
import { PeopleCloudWidgetComponent } from './widgets/people/people-cloud.widget';
import { GroupCloudWidgetComponent } from './widgets/group/group-cloud.widget';
import { PropertiesViewerWidgetComponent } from './widgets/properties-viewer/properties-viewer.widget';
import { RadioButtonsCloudWidgetComponent } from './widgets/radio-buttons/radio-buttons-cloud.widget';

@Injectable({
providedIn: 'root'
Expand All @@ -37,7 +38,8 @@ export class CloudFormRenderingService extends FormRenderingService {
'date': () => DateCloudWidgetComponent,
'people': () => PeopleCloudWidgetComponent,
'functional-group': () => GroupCloudWidgetComponent,
'properties-viewer': () => PropertiesViewerWidgetComponent
'properties-viewer': () => PropertiesViewerWidgetComponent,
'radio-buttons': () => RadioButtonsCloudWidgetComponent
}, true);
}
}
Expand Up @@ -146,7 +146,7 @@ describe('DropdownCloudWidgetComponent', () => {
});

it('should load data from restUrl and populate options', async () => {
const jsonDataSpy = spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of(fakeOptionList));
const jsonDataSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(fakeOptionList));
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id',
name: 'date-name',
Expand All @@ -166,9 +166,9 @@ describe('DropdownCloudWidgetComponent', () => {
fixture.detectChanges();
await fixture.whenStable();

const optOne = fixture.debugElement.queryAll(By.css('[id="option_1"]'));
const optTwo = fixture.debugElement.queryAll(By.css('[id="option_2"]'));
const optThree = fixture.debugElement.queryAll(By.css('[id="option_3"]'));
const optOne = fixture.debugElement.queryAll(By.css('[id="opt_1"]'));
const optTwo = fixture.debugElement.queryAll(By.css('[id="opt_2"]'));
const optThree = fixture.debugElement.queryAll(By.css('[id="opt_3"]'));
const allOptions = fixture.debugElement.queryAll(By.css('mat-option'));

expect(jsonDataSpy).toHaveBeenCalled();
Expand All @@ -195,7 +195,7 @@ describe('DropdownCloudWidgetComponent', () => {
}
});

spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of([
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of([
{
id: 'opt1',
name: 'default1_value'
Expand Down Expand Up @@ -230,7 +230,7 @@ describe('DropdownCloudWidgetComponent', () => {
value: 'opt1'
});

spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of([
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of([
{
id: 'opt1',
name: 'default1_value'
Expand Down Expand Up @@ -265,98 +265,11 @@ describe('DropdownCloudWidgetComponent', () => {
restResponsePath: 'path'
});

const dropdownSpy = spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of({
id: 1,
path: [
const dropdownSpy = spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of( [
{ id: 'opt_1', name: 'option_1' },
{ id: 'opt_2', name: 'option_2' },
{ id: 'opt_3', name: 'option_3' }],
name: ''
}));

widget.ngOnInit();
fixture.detectChanges();

openSelect('#dropdown-id');

fixture.whenStable().then(() => {
expect(dropdownSpy).toHaveBeenCalled();

const optOne: any = fixture.debugElement.queryAll(By.css('[id="opt_1"]'));
expect(optOne[0].context.value).toBe('opt_1');
expect(optOne[0].context.viewValue).toBe('option_1');
const optTwo: any = fixture.debugElement.queryAll(By.css('[id="opt_2"]'));
expect(optTwo[0].context.value).toBe('opt_2');
expect(optTwo[0].context.viewValue).toBe('option_2');
const optThree: any = fixture.debugElement.queryAll(By.css('[id="opt_3"]'));
expect(optThree[0].context.value).toBe('opt_3');
expect(optThree[0].context.viewValue).toBe('option_3');
done();
});
});

it('should map correct label if restLabelProperty is set', (done) => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id',
name: 'date-name',
type: 'dropdown-cloud',
readOnly: 'false',
restUrl: 'fake-rest-url',
optionType: 'rest',
restResponsePath: 'path',
restLabelProperty: 'first_name'
});

const dropdownSpy = spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of({
id: 1,
path: [
{ id: 'opt_1', first_name: 'option_1' },
{ id: 'opt_2', first_name: 'option_2' },
{ id: 'opt_3', first_name: 'option_3' }],
name: ''
}));

widget.ngOnInit();
fixture.detectChanges();

openSelect('#dropdown-id');

fixture.whenStable().then(() => {
expect(dropdownSpy).toHaveBeenCalled();

const optOne: any = fixture.debugElement.queryAll(By.css('[id="opt_1"]'));
expect(optOne[0].context.value).toBe('opt_1');
expect(optOne[0].context.viewValue).toBe('option_1');
const optTwo: any = fixture.debugElement.queryAll(By.css('[id="opt_2"]'));
expect(optTwo[0].context.value).toBe('opt_2');
expect(optTwo[0].context.viewValue).toBe('option_2');
const optThree: any = fixture.debugElement.queryAll(By.css('[id="opt_3"]'));
expect(optThree[0].context.value).toBe('opt_3');
expect(optThree[0].context.viewValue).toBe('option_3');
done();
});
});

it('should map correct id if restIdProperty is set', (done) => {
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'dropdown-id',
name: 'date-name',
type: 'dropdown-cloud',
readOnly: 'false',
restUrl: 'fake-rest-url',
optionType: 'rest',
restResponsePath: 'path',
restIdProperty: 'my_id'
});

const dropdownSpy = spyOn(formCloudService, 'getDropDownJsonData').and.returnValue(of({
id: 1,
path: [
{ my_id: 'opt_1', name: 'option_1' },
{ my_id: 'opt_2', name: 'option_2' },
{ my_id: 'opt_3', name: 'option_3' }],
name: ''
}));
{ id: 'opt_3', name: 'option_3' }]
));

widget.ngOnInit();
fixture.detectChanges();
Expand Down
Expand Up @@ -59,27 +59,14 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI

getValuesFromRestApi() {
if (this.isValidRestType()) {
this.formCloudService.getDropDownJsonData(this.field.restUrl)
this.formCloudService.getRestWidgetData(this.field.form.id, this.field.id)
.pipe(takeUntil(this.onDestroy$))
.subscribe((result: FormFieldOption[]) => {
this.field.options = this.mapJsonData(result);
this.field.options = result;
}, (err) => this.handleError(err));
}
}

mapJsonData(data: any[]): FormFieldOption[] {
const dataToMap: any[] = this.field.restResponsePath ? data[this.field.restResponsePath] : data;
const idProperty = this.field.restIdProperty || 'id';
const restLabelProperty = this.field.restLabelProperty || 'name';

return dataToMap.map((value: any) => {
return {
name: value[restLabelProperty],
id: value[idProperty]
};
});
}

compareDropdownValues(opt1: FormFieldOption | string, opt2: FormFieldOption | string): boolean {
if (!opt1 || !opt2) {
return false;
Expand Down
@@ -0,0 +1,23 @@
<div class="adf-radio-buttons-widget-cloud {{field.className}}"
[class.adf-invalid]="!field.isValid" [class.adf-readonly]="field.readOnly" [id]="field.id">
<div class="adf-radio-button-container">
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}<span *ngIf="isRequired()">*</span></label>
<mat-radio-group class="adf-radio-group" [(ngModel)]="field.value" [disabled]="field.readOnly">
<mat-radio-button
[matTooltip]="field.tooltip"
matTooltipPosition="above"
matTooltipShowDelay="1000"
[id]="field.id + '-' + opt.id"
[name]="field.id"
[value]="opt.id"
[checked]="field.value === opt.id"
(change)="onOptionClick(opt.id)"
color="primary"
class="adf-radio-button" *ngFor="let opt of field.options" >
{{opt.name}}
</mat-radio-button>
</mat-radio-group>
</div>
<error-widget [error]="field.validationSummary" ></error-widget>
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
</div>
@@ -0,0 +1,20 @@
.adf {

&-radio-button-container {
margin-bottom: 15px;
display: flex;
flex-direction: column;
}

&-radio-group {
margin-top: 15px;
margin-left: 5px;
display: inline-flex;
flex-direction: column;
}

&-radio-button {
margin: 5px;
}

}

0 comments on commit 7481001

Please sign in to comment.