mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
AAE-28806 Consume-dynamic-Drop-Down-Radio-Button-form-variables (#10442)
* [AAE-28806] Enable form variables in REST for RadioButton * [AAE-28806] Enable form variables in REST for Dropdown widget * [AAE-28806] removed debugging information * [AAE-28806] Removed code repitition * [AAE-28806] Made fields readonly * [AAE-28806] fixed pipeline --------- Co-authored-by: Andreas Philippi <90837097+andrphilippi@users.noreply.github.com>
This commit is contained in:
@@ -555,11 +555,21 @@ describe('FormModel', () => {
|
|||||||
expect(value).toBeUndefined();
|
expect(value).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should find a process variable by form variable name', () => {
|
it('should find a process variable by full form variable name', () => {
|
||||||
const value = form.getProcessVariableValue('variables.name1');
|
const value = form.getProcessVariableValue('variables.name1');
|
||||||
expect(value).toBe('hello');
|
expect(value).toBe('hello');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should find a process variable by form variable name', () => {
|
||||||
|
const value = form.getProcessVariableValue('name1');
|
||||||
|
expect(value).toBe('hello');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find default form variable by form variable name', () => {
|
||||||
|
const value = form.getProcessVariableValue('name2');
|
||||||
|
expect(value).toBe('29.09.2019T00:00:00.000Z');
|
||||||
|
});
|
||||||
|
|
||||||
it('should find a process variable by name', () => {
|
it('should find a process variable by name', () => {
|
||||||
const value = form.getProcessVariableValue('booleanVar');
|
const value = form.getProcessVariableValue('booleanVar');
|
||||||
expect(value).toEqual(true);
|
expect(value).toEqual(true);
|
||||||
|
@@ -37,11 +37,13 @@ import { HarnessLoader } from '@angular/cdk/testing';
|
|||||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||||
import { MatSelectHarness } from '@angular/material/select/testing';
|
import { MatSelectHarness } from '@angular/material/select/testing';
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
|
import { FormUtilsService } from '../../../services/form-utils.service';
|
||||||
|
|
||||||
describe('DropdownCloudWidgetComponent', () => {
|
describe('DropdownCloudWidgetComponent', () => {
|
||||||
let formService: FormService;
|
let formService: FormService;
|
||||||
let widget: DropdownCloudWidgetComponent;
|
let widget: DropdownCloudWidgetComponent;
|
||||||
let formCloudService: FormCloudService;
|
let formCloudService: FormCloudService;
|
||||||
|
let formUtilsService: FormUtilsService;
|
||||||
let fixture: ComponentFixture<DropdownCloudWidgetComponent>;
|
let fixture: ComponentFixture<DropdownCloudWidgetComponent>;
|
||||||
let element: HTMLElement;
|
let element: HTMLElement;
|
||||||
let loader: HarnessLoader;
|
let loader: HarnessLoader;
|
||||||
@@ -56,6 +58,7 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
|
|
||||||
formService = TestBed.inject(FormService);
|
formService = TestBed.inject(FormService);
|
||||||
formCloudService = TestBed.inject(FormCloudService);
|
formCloudService = TestBed.inject(FormCloudService);
|
||||||
|
formUtilsService = TestBed.inject(FormUtilsService);
|
||||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ 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', readOnly: false, id: 'form-id' }), {
|
||||||
id: 'dropdown-id',
|
id: 'dropdown-id',
|
||||||
name: 'date-name',
|
name: 'date-name',
|
||||||
type: 'dropdown',
|
type: 'dropdown',
|
||||||
@@ -91,6 +94,26 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
expect(formCloudService.getRestWidgetData).toHaveBeenCalled();
|
expect(formCloudService.getRestWidgetData).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call getRestWidgetData with correct body parameters when body is empty', () => {
|
||||||
|
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(fakeOptionList));
|
||||||
|
widget.field.optionType = 'rest';
|
||||||
|
|
||||||
|
widget.ngOnInit();
|
||||||
|
expect(formCloudService.getRestWidgetData).toHaveBeenCalledWith('form-id', 'dropdown-id', {});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call getRestWidgetData with correct body parameters when variables are mapped', () => {
|
||||||
|
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(fakeOptionList));
|
||||||
|
widget.field.optionType = 'rest';
|
||||||
|
const body = { var1: 'value1', var2: 'value2' };
|
||||||
|
spyOn(formUtilsService, 'getRestUrlVariablesMap').and.returnValue(body);
|
||||||
|
|
||||||
|
widget.ngOnInit();
|
||||||
|
|
||||||
|
expect(formUtilsService.getRestUrlVariablesMap).toHaveBeenCalledWith(widget.field.form, widget.field.restUrl, {});
|
||||||
|
expect(formCloudService.getRestWidgetData).toHaveBeenCalledWith('form-id', 'dropdown-id', body);
|
||||||
|
});
|
||||||
|
|
||||||
it('should select the default value when an option is chosen as default', async () => {
|
it('should select the default value when an option is chosen as default', async () => {
|
||||||
widget.field.value = 'option_2';
|
widget.field.value = 'option_2';
|
||||||
|
|
||||||
@@ -623,6 +646,9 @@ describe('DropdownCloudWidgetComponent', () => {
|
|||||||
await dropdown.open();
|
await dropdown.open();
|
||||||
const allOptions = await dropdown.getOptions();
|
const allOptions = await dropdown.getOptions();
|
||||||
|
|
||||||
|
expect(formCloudService.getRestWidgetData).toHaveBeenCalledWith('fake-form-id', 'child-dropdown-id', {
|
||||||
|
parentDropdown: 'mock-value'
|
||||||
|
});
|
||||||
expect(jsonDataSpy).toHaveBeenCalledWith('fake-form-id', 'child-dropdown-id', { parentDropdown: 'mock-value' });
|
expect(jsonDataSpy).toHaveBeenCalledWith('fake-form-id', 'child-dropdown-id', { parentDropdown: 'mock-value' });
|
||||||
expect(await (await allOptions[0].host()).getAttribute('id')).toEqual('LO');
|
expect(await (await allOptions[0].host()).getAttribute('id')).toEqual('LO');
|
||||||
expect(await allOptions[0].getText()).toEqual('LONDON');
|
expect(await allOptions[0].getText()).toEqual('LONDON');
|
||||||
|
@@ -40,6 +40,7 @@ import { filter, map } from 'rxjs/operators';
|
|||||||
import { TaskVariableCloud } from '../../../models/task-variable-cloud.model';
|
import { TaskVariableCloud } from '../../../models/task-variable-cloud.model';
|
||||||
import { FormCloudService } from '../../../services/form-cloud.service';
|
import { FormCloudService } from '../../../services/form-cloud.service';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { FormUtilsService } from '../../../services/form-utils.service';
|
||||||
|
|
||||||
export const DEFAULT_OPTION = {
|
export const DEFAULT_OPTION = {
|
||||||
id: 'empty',
|
id: 'empty',
|
||||||
@@ -69,8 +70,9 @@ export const HIDE_FILTER_LIMIT = 5;
|
|||||||
})
|
})
|
||||||
export class DropdownCloudWidgetComponent extends WidgetComponent implements OnInit, ReactiveFormWidget {
|
export class DropdownCloudWidgetComponent extends WidgetComponent implements OnInit, ReactiveFormWidget {
|
||||||
public formService = inject(FormService);
|
public formService = inject(FormService);
|
||||||
private formCloudService = inject(FormCloudService);
|
private readonly formCloudService = inject(FormCloudService);
|
||||||
private appConfig = inject(AppConfigService);
|
private readonly appConfig = inject(AppConfigService);
|
||||||
|
private readonly formUtilsService = inject(FormUtilsService);
|
||||||
private destroyRef = inject(DestroyRef);
|
private destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
typeId = 'DropdownCloudWidgetComponent';
|
typeId = 'DropdownCloudWidgetComponent';
|
||||||
@@ -364,7 +366,8 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
|||||||
const parentWidgetId = this.linkedWidgetId;
|
const parentWidgetId = this.linkedWidgetId;
|
||||||
bodyParam[parentWidgetId] = parentWidgetValue;
|
bodyParam[parentWidgetId] = parentWidgetValue;
|
||||||
}
|
}
|
||||||
return bodyParam;
|
|
||||||
|
return this.formUtilsService.getRestUrlVariablesMap(this.field.form, this.field.restUrl, bodyParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadFieldOptionsForLinkedWidget() {
|
private loadFieldOptionsForLinkedWidget() {
|
||||||
|
@@ -24,11 +24,13 @@ import { of, throwError } from 'rxjs';
|
|||||||
import { HarnessLoader } from '@angular/cdk/testing';
|
import { HarnessLoader } from '@angular/cdk/testing';
|
||||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||||
import { MatRadioButtonHarness, MatRadioGroupHarness } from '@angular/material/radio/testing';
|
import { MatRadioButtonHarness, MatRadioGroupHarness } from '@angular/material/radio/testing';
|
||||||
|
import { FormUtilsService } from '../../../services/form-utils.service';
|
||||||
|
|
||||||
describe('RadioButtonsCloudWidgetComponent', () => {
|
describe('RadioButtonsCloudWidgetComponent', () => {
|
||||||
let fixture: ComponentFixture<RadioButtonsCloudWidgetComponent>;
|
let fixture: ComponentFixture<RadioButtonsCloudWidgetComponent>;
|
||||||
let widget: RadioButtonsCloudWidgetComponent;
|
let widget: RadioButtonsCloudWidgetComponent;
|
||||||
let formCloudService: FormCloudService;
|
let formCloudService: FormCloudService;
|
||||||
|
let formUtilsService: FormUtilsService;
|
||||||
let element: HTMLElement;
|
let element: HTMLElement;
|
||||||
let loader: HarnessLoader;
|
let loader: HarnessLoader;
|
||||||
const restOption: FormFieldOption[] = [
|
const restOption: FormFieldOption[] = [
|
||||||
@@ -47,6 +49,7 @@ describe('RadioButtonsCloudWidgetComponent', () => {
|
|||||||
imports: [ProcessServiceCloudTestingModule]
|
imports: [ProcessServiceCloudTestingModule]
|
||||||
});
|
});
|
||||||
formCloudService = TestBed.inject(FormCloudService);
|
formCloudService = TestBed.inject(FormCloudService);
|
||||||
|
formUtilsService = TestBed.inject(FormUtilsService);
|
||||||
fixture = TestBed.createComponent(RadioButtonsCloudWidgetComponent);
|
fixture = TestBed.createComponent(RadioButtonsCloudWidgetComponent);
|
||||||
widget = fixture.componentInstance;
|
widget = fixture.componentInstance;
|
||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
@@ -134,6 +137,21 @@ describe('RadioButtonsCloudWidgetComponent', () => {
|
|||||||
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(restOption));
|
spyOn(formCloudService, 'getRestWidgetData').and.returnValue(of(restOption));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call getRestWidgetData with correct parameters and update field options on success', () => {
|
||||||
|
const formId = 'form-id';
|
||||||
|
const fieldId = 'field-id';
|
||||||
|
widget.field = new FormFieldModel(new FormModel({ id: formId }), { id: fieldId, restUrl: '<url>' });
|
||||||
|
const body = { var1: 'value1', var2: 'value2' };
|
||||||
|
spyOn(formUtilsService, 'getRestUrlVariablesMap').and.returnValue(body);
|
||||||
|
spyOn(widget.field, 'updateForm');
|
||||||
|
|
||||||
|
widget.getValuesFromRestApi();
|
||||||
|
|
||||||
|
expect(formCloudService.getRestWidgetData).toHaveBeenCalledWith(formId, fieldId, body);
|
||||||
|
expect(widget.field.options).toEqual(restOption);
|
||||||
|
expect(widget.field.updateForm).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
describe('when widget is readonly', () => {
|
describe('when widget is readonly', () => {
|
||||||
it('should call rest api when form is NOT readonly', () => {
|
it('should call rest api when form is NOT readonly', () => {
|
||||||
widget.field = new FormFieldModel(new FormModel({}, undefined, false), getRadioButtonsWidgetConfig(true));
|
widget.field = new FormFieldModel(new FormModel({}, undefined, false), getRadioButtonsWidgetConfig(true));
|
||||||
|
@@ -22,6 +22,7 @@ import { ErrorMessageModel, FormFieldOption, FormService, WidgetComponent } from
|
|||||||
import { FormCloudService } from '../../../services/form-cloud.service';
|
import { FormCloudService } from '../../../services/form-cloud.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { FormUtilsService } from '../../../services/form-utils.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'radio-buttons-cloud-widget',
|
selector: 'radio-buttons-cloud-widget',
|
||||||
@@ -46,7 +47,12 @@ export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements
|
|||||||
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
constructor(public formService: FormService, private formCloudService: FormCloudService, private translateService: TranslateService) {
|
constructor(
|
||||||
|
public formService: FormService,
|
||||||
|
private readonly formCloudService: FormCloudService,
|
||||||
|
private readonly translateService: TranslateService,
|
||||||
|
private readonly formUtilsService: FormUtilsService
|
||||||
|
) {
|
||||||
super(formService);
|
super(formService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +63,10 @@ export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
getValuesFromRestApi() {
|
getValuesFromRestApi() {
|
||||||
|
const body = this.formUtilsService.getRestUrlVariablesMap(this.field.form, this.field.restUrl, {});
|
||||||
|
|
||||||
this.formCloudService
|
this.formCloudService
|
||||||
.getRestWidgetData(this.field.form.id, this.field.id)
|
.getRestWidgetData(this.field.form.id, this.field.id, body)
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result: FormFieldOption[]) => {
|
(result: FormFieldOption[]) => {
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { TestBed } from '@angular/core/testing';
|
||||||
|
import { FormUtilsService } from './form-utils.service';
|
||||||
|
import { FormModel, FormVariableModel } from '@alfresco/adf-core';
|
||||||
|
|
||||||
|
describe('FormUtilsService', () => {
|
||||||
|
let service: FormUtilsService;
|
||||||
|
const variables: FormVariableModel[] = [
|
||||||
|
{ id: '1', name: 'var1', type: 'string', value: 'value1' },
|
||||||
|
{ id: '2', name: 'var2', type: 'string', value: 'value2' }
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the getRestUrlVariablesMap method
|
||||||
|
*
|
||||||
|
* @param restUrl The rest URL for getRestUrlVariablesMap
|
||||||
|
* @param inputBody The input body for getRestUrlVariablesMap
|
||||||
|
* @param expected The expected result of getRestUrlVariablesMap
|
||||||
|
*/
|
||||||
|
function testRestUrlVariablesMap(restUrl: string, inputBody: { [key: string]: any }, expected: { [key: string]: any }) {
|
||||||
|
const formModel = new FormModel({ variables });
|
||||||
|
spyOn(formModel, 'getProcessVariableValue').and.callFake((name) => {
|
||||||
|
return variables.find((variable) => variable.name === name)?.value;
|
||||||
|
});
|
||||||
|
const result = service.getRestUrlVariablesMap(formModel, restUrl, inputBody);
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(FormUtilsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty map if there are no variables', () => {
|
||||||
|
const formModel = new FormModel({ variables: [] });
|
||||||
|
const restUrl = 'https://example.com/api';
|
||||||
|
const inputBody = {};
|
||||||
|
|
||||||
|
const result = service.getRestUrlVariablesMap(formModel, restUrl, inputBody);
|
||||||
|
|
||||||
|
expect(result).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map variable values to the input body if they are present in the restUrl', () => {
|
||||||
|
testRestUrlVariablesMap('https://example.com/api?var1=${var1}&var2=${var2}', {}, { var1: 'value1', var2: 'value2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not map variable values if they are not present in the restUrl', () => {
|
||||||
|
testRestUrlVariablesMap('https://example.com/api', {}, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should merge the mapped variables with the input body', () => {
|
||||||
|
testRestUrlVariablesMap(
|
||||||
|
'https://example.com/api?var1=${var1}',
|
||||||
|
{ existingKey: 'existingValue' },
|
||||||
|
{ existingKey: 'existingValue', var1: 'value1' }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,32 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { Injectable } from '@angular/core';
|
||||||
|
import { FormModel, FormVariableModel } from '@alfresco/adf-core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class FormUtilsService {
|
||||||
|
getRestUrlVariablesMap(formModel: FormModel, restUrl: string, inputBody: { [key: string]: any }) {
|
||||||
|
return formModel.variables.reduce((map: { [key: string]: any }, variable: FormVariableModel) => {
|
||||||
|
const variablePattern = new RegExp(`\\$\\{${variable.name}\\}`);
|
||||||
|
if (variablePattern.test(restUrl)) map[variable.name] = formModel.getProcessVariableValue(variable.name);
|
||||||
|
return map;
|
||||||
|
}, inputBody);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user