mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-50868 Fix some visibility conditions scenarios with form variables (#12206)
* AAE-50868 Fix some visibility conditions senarios with form variables * form 0 check updates * copilot review suggestions
This commit is contained in:
@@ -20,4 +20,5 @@ export interface FormVariableModel {
|
||||
name: string;
|
||||
type: string;
|
||||
value?: any;
|
||||
runtimeSet?: boolean;
|
||||
}
|
||||
|
||||
@@ -600,6 +600,33 @@ describe('FormModel', () => {
|
||||
const missing = form.getProcessVariableValue('missing');
|
||||
expect(missing).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return zero process variable value instead of the form default', () => {
|
||||
const formWithZero = new FormModel({
|
||||
variables: [{ id: 'amount-var', name: 'amount', type: 'integer', value: 99 }],
|
||||
processVariables: [{ name: 'variables.amount', value: 0, type: 'integer' }]
|
||||
});
|
||||
|
||||
expect(formWithZero.getProcessVariableValue('amount')).toBe(0);
|
||||
});
|
||||
|
||||
it('should return false process variable value instead of the form default', () => {
|
||||
const formWithFalse = new FormModel({
|
||||
variables: [{ id: 'flag-var', name: 'flag', type: 'boolean', value: true }],
|
||||
processVariables: [{ name: 'variables.flag', value: false, type: 'boolean' }]
|
||||
});
|
||||
|
||||
expect(formWithFalse.getProcessVariableValue('flag')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return empty string process variable value instead of the form default', () => {
|
||||
const formWithEmpty = new FormModel({
|
||||
variables: [{ id: 'text-var', name: 'text', type: 'string', value: 'default' }],
|
||||
processVariables: [{ name: 'variables.text', value: '', type: 'string' }]
|
||||
});
|
||||
|
||||
expect(formWithEmpty.getProcessVariableValue('text')).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('add values not present', () => {
|
||||
|
||||
@@ -307,22 +307,17 @@ export class FormModel implements ProcessFormModel {
|
||||
* @returns process variable value
|
||||
*/
|
||||
getProcessVariableValue(name: string): any {
|
||||
let value;
|
||||
if (this.processVariables?.length) {
|
||||
const names = [`variables.${name}`, name];
|
||||
|
||||
const processVariable = this.processVariables.find((entry) => names.includes(entry.name));
|
||||
|
||||
if (processVariable) {
|
||||
value = this.parseValue(processVariable.type, processVariable.value);
|
||||
return this.parseValue(processVariable.type, processVariable.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
value = this.getDefaultFormVariableValue(name);
|
||||
}
|
||||
|
||||
return value;
|
||||
return this.getDefaultFormVariableValue(name);
|
||||
}
|
||||
|
||||
protected parseValue(type: string, value: any): any {
|
||||
@@ -535,9 +530,20 @@ export class FormModel implements ProcessFormModel {
|
||||
const variable = this.getFormVariable(variableId);
|
||||
if (variable) {
|
||||
variable.value = value;
|
||||
variable.runtimeSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a form variable has been given a value at runtime, for example by a form rule.
|
||||
*
|
||||
* @param identifier The `name` or `id` value
|
||||
* @returns `true` when the value was set at runtime rather than coming from the form definition
|
||||
*/
|
||||
isVariableSetAtRuntime(identifier: string): boolean {
|
||||
return !!this.getFormVariable(identifier)?.runtimeSet;
|
||||
}
|
||||
|
||||
private loadInjectedFieldValidators(injectedFieldValidators: FormFieldValidator[]): void {
|
||||
this.fieldValidators = injectedFieldValidators ? [...FORM_FIELD_VALIDATORS, ...injectedFieldValidators] : [...FORM_FIELD_VALIDATORS];
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@
|
||||
export class TaskProcessVariableModel {
|
||||
id?: string;
|
||||
type?: string;
|
||||
value: string;
|
||||
value: any;
|
||||
}
|
||||
|
||||
@@ -1002,4 +1002,169 @@ describe('WidgetVisibilityService', () => {
|
||||
expect(textField.isVisible).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Visibility calculation from form variables', () => {
|
||||
const hiddenWhileRequestor = new WidgetVisibilityModel({
|
||||
leftType: 'variable',
|
||||
leftValue: 'person_type',
|
||||
operator: '!=',
|
||||
rightType: 'value',
|
||||
rightValue: 'Requestor',
|
||||
nextConditionOperator: '',
|
||||
nextCondition: null
|
||||
});
|
||||
|
||||
const requestorProcessVariables = [{ id: 'variables.person_type', value: 'Requestor' }];
|
||||
|
||||
let formJson: any;
|
||||
let form: FormModel;
|
||||
|
||||
beforeEach(() => {
|
||||
formJson = {
|
||||
id: 'person-type-form',
|
||||
variables: [{ id: 'person-type-var', name: 'person_type', value: null }],
|
||||
processVariables: [{ name: 'variables.person_type', value: 'Requestor' }]
|
||||
};
|
||||
form = new FormModel(formJson);
|
||||
service.cleanProcessVariable();
|
||||
});
|
||||
|
||||
it('should resolve a variable from the form when the cached process variables no longer hold it', () => {
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
|
||||
service.refreshVisibility(new FormModel({ id: 'another-form' }), [{ id: 'variables.other', value: 'other' }]);
|
||||
|
||||
expect(service.evaluateVisibility(form, hiddenWhileRequestor)).toBe(false);
|
||||
});
|
||||
|
||||
it('should resolve a variable from the form when the refreshed data omits it', () => {
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
service.refreshVisibility(form, [{ id: 'processOutput', value: 'result' }]);
|
||||
|
||||
expect(service.evaluateVisibility(form, hiddenWhileRequestor)).toBe(false);
|
||||
});
|
||||
|
||||
it('should prefer a process variable over the value defined in the form definition', () => {
|
||||
const formWithDefault = new FormModel({
|
||||
id: 'person-type-form-with-default',
|
||||
variables: [{ id: 'person-type-var', name: 'person_type', value: 'Approver' }],
|
||||
processVariables: [{ name: 'variables.person_type', value: 'Requestor' }]
|
||||
});
|
||||
|
||||
expect(service.getVariableValue(formWithDefault, 'person_type', requestorProcessVariables)).toBe('Requestor');
|
||||
});
|
||||
|
||||
it('should prefer a variable changed at runtime over a process variable of the same name', () => {
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
|
||||
form.changeVariableValue('person-type-var', 'Approver');
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
|
||||
expect(service.evaluateVisibility(form, hiddenWhileRequestor)).toBe(true);
|
||||
});
|
||||
|
||||
it('should prefer a variable cleared at runtime over a process variable of the same name', () => {
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
|
||||
form.changeVariableValue('person-type-var', '');
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
|
||||
expect(service.evaluateVisibility(form, hiddenWhileRequestor)).toBe(true);
|
||||
});
|
||||
|
||||
it('should keep a variable changed at runtime when the form is rebuilt from the same definition', () => {
|
||||
service.refreshVisibility(form, requestorProcessVariables);
|
||||
form.changeVariableValue('person-type-var', 'Approver');
|
||||
|
||||
const rebuiltForm = new FormModel(formJson);
|
||||
service.refreshVisibility(rebuiltForm, [{ id: 'processOutput', value: 'result' }]);
|
||||
|
||||
expect(service.evaluateVisibility(rebuiltForm, hiddenWhileRequestor)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not convert the type of a variable changed at runtime', () => {
|
||||
const numericForm = new FormModel({ id: 'numeric-form', variables: [{ id: 'amount-var', name: 'amount', type: 'integer', value: 0 }] });
|
||||
const booleanForm = new FormModel({ id: 'boolean-form', variables: [{ id: 'flag-var', name: 'flag', type: 'boolean', value: true }] });
|
||||
|
||||
service.refreshVisibility(numericForm);
|
||||
service.refreshVisibility(booleanForm);
|
||||
|
||||
numericForm.changeVariableValue('amount-var', 5);
|
||||
booleanForm.changeVariableValue('flag-var', false);
|
||||
|
||||
service.refreshVisibility(numericForm);
|
||||
service.refreshVisibility(booleanForm);
|
||||
|
||||
expect(service.getVariableValue(numericForm, 'amount')).toBe(5);
|
||||
expect(service.getVariableValue(booleanForm, 'flag', [])).toBe(false);
|
||||
});
|
||||
|
||||
it('should evaluate a numeric variable changed at runtime without string comparison', () => {
|
||||
const numericForm = new FormModel({
|
||||
id: 'numeric-visibility-form',
|
||||
variables: [{ id: 'amount-var', name: 'amount', type: 'integer', value: 0 }]
|
||||
});
|
||||
const amountOverTen = new WidgetVisibilityModel({
|
||||
leftType: 'variable',
|
||||
leftValue: 'amount',
|
||||
operator: '>',
|
||||
rightType: 'value',
|
||||
rightValue: '10',
|
||||
nextConditionOperator: '',
|
||||
nextCondition: null
|
||||
});
|
||||
|
||||
service.refreshVisibility(numericForm);
|
||||
numericForm.changeVariableValue('amount-var', 5);
|
||||
service.refreshVisibility(numericForm);
|
||||
|
||||
expect(service.evaluateVisibility(numericForm, amountOverTen)).toBe(false);
|
||||
});
|
||||
|
||||
it('should resolve a zero process variable from the form when the refreshed data omits it', () => {
|
||||
const zeroForm = new FormModel({
|
||||
id: 'zero-form',
|
||||
variables: [{ id: 'amount-var', name: 'amount', type: 'integer', value: 99 }],
|
||||
processVariables: [{ name: 'variables.amount', value: 0, type: 'integer' }]
|
||||
});
|
||||
const amountIsZero = new WidgetVisibilityModel({
|
||||
leftType: 'variable',
|
||||
leftValue: 'amount',
|
||||
operator: '==',
|
||||
rightType: 'value',
|
||||
rightValue: '0',
|
||||
nextConditionOperator: '',
|
||||
nextCondition: null
|
||||
});
|
||||
|
||||
service.refreshVisibility(zeroForm, [{ id: 'variables.amount', value: 0 }]);
|
||||
service.refreshVisibility(zeroForm, [{ id: 'processOutput', value: 'result' }]);
|
||||
|
||||
expect(service.getVariableValue(zeroForm, 'amount', [])).toBe(0);
|
||||
expect(service.evaluateVisibility(zeroForm, amountIsZero)).toBe(true);
|
||||
});
|
||||
|
||||
it('should resolve a false process variable from the form when the refreshed data omits it', () => {
|
||||
const falseForm = new FormModel({
|
||||
id: 'false-form',
|
||||
variables: [{ id: 'flag-var', name: 'flag', type: 'boolean', value: true }],
|
||||
processVariables: [{ name: 'variables.flag', value: false, type: 'boolean' }]
|
||||
});
|
||||
const flagIsFalse = new WidgetVisibilityModel({
|
||||
leftType: 'variable',
|
||||
leftValue: 'flag',
|
||||
operator: '==',
|
||||
rightType: 'value',
|
||||
rightValue: 'false',
|
||||
nextConditionOperator: '',
|
||||
nextCondition: null
|
||||
});
|
||||
|
||||
service.refreshVisibility(falseForm, [{ id: 'variables.flag', value: false }]);
|
||||
service.refreshVisibility(falseForm, [{ id: 'processOutput', value: 'result' }]);
|
||||
|
||||
expect(service.getVariableValue(falseForm, 'flag', [])).toBe(false);
|
||||
expect(service.evaluateVisibility(falseForm, flagIsFalse)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ import { FormService } from './form.service';
|
||||
export class WidgetVisibilityService {
|
||||
private readonly formService = inject(FormService);
|
||||
|
||||
private processVarList: TaskProcessVariableModel[];
|
||||
private processVarList: TaskProcessVariableModel[] = [];
|
||||
private form: FormModel;
|
||||
|
||||
public refreshVisibility(form: FormModel, processVarList?: TaskProcessVariableModel[]) {
|
||||
@@ -110,7 +110,7 @@ export class WidgetVisibilityService {
|
||||
}
|
||||
}
|
||||
|
||||
getLeftValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string {
|
||||
getLeftValue(form: FormModel, visibilityObj: WidgetVisibilityModel): any {
|
||||
let leftValue = '';
|
||||
if (visibilityObj.leftType === WidgetTypeEnum.variable) {
|
||||
leftValue = this.getVariableValue(form, visibilityObj.leftValue, this.processVarList);
|
||||
@@ -124,7 +124,7 @@ export class WidgetVisibilityService {
|
||||
return leftValue;
|
||||
}
|
||||
|
||||
getRightValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string {
|
||||
getRightValue(form: FormModel, visibilityObj: WidgetVisibilityModel): any {
|
||||
let valueFound = '';
|
||||
|
||||
if (visibilityObj.rightType === WidgetTypeEnum.variable) {
|
||||
@@ -270,20 +270,21 @@ export class WidgetVisibilityService {
|
||||
return field.id && fieldToFind ? field.id.toUpperCase() === fieldToFind.toUpperCase() : false;
|
||||
}
|
||||
|
||||
public getVariableValue(form: FormModel, name: string, processVarList: TaskProcessVariableModel[]): string {
|
||||
const processVariableValue = this.getProcessVariableValue(name, processVarList);
|
||||
const variableDefaultValue = form.getDefaultFormVariableValue(name);
|
||||
public getVariableValue(form: FormModel, name: string, processVarList: TaskProcessVariableModel[] = []): any {
|
||||
if (form.isVariableSetAtRuntime(name)) {
|
||||
return form.getDefaultFormVariableValue(name);
|
||||
}
|
||||
|
||||
return processVariableValue === undefined ? variableDefaultValue : processVariableValue;
|
||||
const processVariableValue = this.getProcessVariableValue(name, processVarList);
|
||||
|
||||
return processVariableValue === undefined ? form.getProcessVariableValue(name) : processVariableValue;
|
||||
}
|
||||
|
||||
private getProcessVariableValue(name: string, processVarList: TaskProcessVariableModel[]): string {
|
||||
if (processVarList) {
|
||||
const processVariable = processVarList.find((variable) => variable.id === name || variable.id === `variables.${name}`);
|
||||
private getProcessVariableValue(name: string, processVarList: TaskProcessVariableModel[]): any {
|
||||
const processVariable = processVarList.find((variable) => variable.id === name || variable.id === `variables.${name}`);
|
||||
|
||||
if (processVariable) {
|
||||
return processVariable.value;
|
||||
}
|
||||
if (processVariable) {
|
||||
return processVariable.value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user