Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AAE-612] Support for Form Outcome Visibility Conditions #5934

Merged
merged 1 commit into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,30 @@ describe('FormOutcomeModel', () => {
it('should setup with json config', () => {
const json = {
id: '<id>',
name: '<name>'
name: '<name>',
visibilityCondition: {
leftType: 'field',
leftValue: 'TextOne',
operator: '==',
rightValue: 'showTab',
rightType: 'value',
nextConditionOperator: '',
nextCondition: null
}
};
const model = new FormOutcomeModel(null, json);
expect(model.id).toBe(json.id);
expect(model.name).toBe(json.name);
expect(model.visibilityCondition).toBeDefined();
});

it('should not setup with null json config', () => {
const model = new FormOutcomeModel(null, null);
expect(model.id).toBeUndefined();
expect(model.name).toBeUndefined();
expect(model.isVisible).toBeDefined();
expect(model.isVisible).toBe(true);
expect(model.visibilityCondition).toBeUndefined();
});

it('should store the form reference', () => {
Expand Down
4 changes: 4 additions & 0 deletions lib/core/form/components/widgets/core/form-outcome.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import { FormWidgetModel } from './form-widget.model';
import { FormModel } from './form.model';
import { WidgetVisibilityModel } from './../../../models/widget-visibility.model';

export class FormOutcomeModel extends FormWidgetModel {

Expand All @@ -28,13 +29,16 @@ export class FormOutcomeModel extends FormWidgetModel {

isSystem: boolean = false;
isSelected: boolean = false;
isVisible: boolean = true;
visibilityCondition: WidgetVisibilityModel;

constructor(form: FormModel, json?: any) {
super(form, json);

if (json) {
this.isSystem = json.isSystem ? true : false;
this.isSelected = form && json.name === form.selectedOutcome ? true : false;
this.visibilityCondition = new WidgetVisibilityModel(json.visibilityCondition);
}
}
}
2 changes: 1 addition & 1 deletion lib/core/form/components/widgets/core/tab.model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('TabModel', () => {
expect(model.isVisible).toBe(true);
});

it('should not setup with json config', () => {
it('should not setup with null json config', () => {
const model = new TabModel(null, null);
expect(model.id).toBeUndefined();
expect(model.title).toBeUndefined();
Expand Down
23 changes: 21 additions & 2 deletions lib/core/form/services/widget-visibility-cloud.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
FormFieldModel,
FormFieldTypes,
FormModel,
TabModel
TabModel,
FormOutcomeModel
} from './../components/widgets/core/index';
import { TaskProcessVariableModel } from './../models/task-process-variable.model';
import { WidgetVisibilityModel, WidgetTypeEnum } from './../models/widget-visibility.model';
Expand All @@ -31,7 +32,7 @@ import {
fakeFormJson, fakeTaskProcessVariableModels,
formTest, formValues, complexVisibilityJsonVisible,
nextConditionForm, complexVisibilityJsonNotVisible,
headerVisibilityCond } from 'core/mock/form/widget-visibility-cloud.service.mock';
headerVisibilityCond } from '../../mock/form/widget-visibility-cloud.service.mock';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { TranslateModule } from '@ngx-translate/core';

Expand Down Expand Up @@ -672,6 +673,24 @@ describe('WidgetVisibilityCloudService', () => {
expect(fakeFormWithField.tabs[0].isVisible).toBeFalsy();
});

it('should refresh the visibility for Outcomes in forms', () => {
visibilityObjTest.leftType = WidgetTypeEnum.field;
visibilityObjTest.leftValue = 'FIELD_TEST';
visibilityObjTest.operator = '!=';
visibilityObjTest.rightValue = 'RIGHT_FORM_FIELD_VALUE';
const outcome = new FormOutcomeModel(fakeFormWithField, {
isSystem: false,
isSelected: false,
isVisible: true
});

outcome.visibilityCondition = visibilityObjTest;
fakeFormWithField.outcomes.push(outcome);
service.refreshVisibility(fakeFormWithField);
const outcomeIndex = fakeFormWithField.outcomes.length - 1;
expect(fakeFormWithField.outcomes[outcomeIndex].isVisible).toBeFalsy();
});

it('should use the form value to evaluate the visibility condition if the form value is defined', (done) => {
service.getTaskProcessVariable('9999').subscribe(
(res: TaskProcessVariableModel[]) => {
Expand Down
10 changes: 9 additions & 1 deletion lib/core/form/services/widget-visibility.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { LogService } from '../../services/log.service';
import { Injectable } from '@angular/core';
import moment from 'moment-es6';
import { Observable, from, throwError } from 'rxjs';
import { FormFieldModel, FormModel, TabModel, ContainerModel } from '../components/widgets/core/index';
import { FormFieldModel, FormModel, TabModel, ContainerModel, FormOutcomeModel } from '../components/widgets/core/index';
import { TaskProcessVariableModel } from '../models/task-process-variable.model';
import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibility.model';
import { map, catchError } from 'rxjs/operators';
Expand All @@ -43,6 +43,10 @@ export class WidgetVisibilityService {
form.tabs.map((tabModel) => this.refreshEntityVisibility(tabModel));
}

if (form && form.outcomes && form.outcomes.length > 0) {
form.outcomes.map((outcomeModel) => this.refreshOutcomeVisibility(outcomeModel));
}

if (form) {
form.getFormFields().map((field) => this.refreshEntityVisibility(field));
}
Expand All @@ -53,6 +57,10 @@ export class WidgetVisibilityService {
element.isVisible = visible && this.isParentTabVisible(this.form, element);
}

refreshOutcomeVisibility(element: FormOutcomeModel) {
element.isVisible = this.evaluateVisibility(element.form, element.visibilityCondition);
}

evaluateVisibility(form: FormModel, visibilityObj: WidgetVisibilityModel): boolean {
const isLeftFieldPresent = visibilityObj && (visibilityObj.leftType || visibilityObj.leftValue);
if (!isLeftFieldPresent || isLeftFieldPresent === 'null') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ <h4>
</mat-card-content>
<mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions">
<ng-content select="adf-cloud-form-custom-outcomes"></ng-content>
<button [id]="'adf-form-'+ outcome.name | formatSpace" *ngFor="let outcome of form.outcomes"
[color]="getColorForOutcome(outcome.name)" mat-button [disabled]="!isOutcomeButtonEnabled(outcome)"
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
(click)="onOutcomeClicked(outcome)">
{{outcome.name | translate | uppercase }}
</button>
<ng-container *ngFor="let outcome of form.outcomes">
<button *ngIf="outcome.isVisible" [id]="'adf-form-'+ outcome.name | formatSpace" [color]="getColorForOutcome(outcome.name)"
mat-button [disabled]="!isOutcomeButtonEnabled(outcome)"
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
(click)="onOutcomeClicked(outcome)">
{{outcome.name | translate | uppercase }}
</button>
</ng-container>
</mat-card-actions>
</mat-card>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,29 @@ describe('FormCloudComponent', () => {
const label = fixture.debugElement.query(By.css(`${container} label`));
expect(label.nativeElement.innerText).toEqual('Attach file');
});

it('should be able to set visibility conditions for Outcomes', async () => {
spyOn(formCloudService, 'getForm').and.returnValue(of(conditionalUploadWidgetsMock));
const formId = '123';
const appName = 'test-app';
formComponent.formId = formId;
formComponent.appVersion = 1;

formComponent.ngOnChanges({ 'appName': new SimpleChange(null, appName, true) });
expect(formCloudService.getForm).toHaveBeenCalledWith(appName, formId, 1);

fixture.detectChanges();
let outcome = fixture.debugElement.query(By.css(`#adf-form-custom_outcome`));
expect(outcome).toBeNull();

const inputElement = fixture.debugElement.query(By.css('[id="field-Text0xlk8n-container"] input'));
inputElement.nativeElement.value = 'hi';
inputElement.nativeElement.dispatchEvent(new Event('input'));
fixture.detectChanges();

outcome = fixture.debugElement.query(By.css(`#adf-form-custom_outcome`));
expect(outcome.nativeElement.innerText).toEqual('CUSTOM OUTCOME');
});
});

describe('Multilingual Form', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,21 @@ export const conditionalUploadWidgetsMock = {
}
}
],
'outcomes': [],
'outcomes': [
{
'id': '5f2f1c2d-5a79-4ed1-a262-4fef190d41eb',
'name': 'Custom Outcome',
'visibilityCondition': {
'leftType': 'field',
'leftValue': 'Text0xlk8n',
'operator': '==',
'rightValue': 'hi',
'rightType': 'value',
'nextConditionOperator': '',
'nextCondition': null
}
}
],
'metadata': {},
'variables': []
}
Expand Down