[ADF-4468] FormCloud - Be able to display the value of a form variables (#4676)

* Fix the value passed as processDefinition
Be sure we fetch the form variables

* * Rename formId to formKey.

* * Reverted form Changes

* * Fixed failing unit test

* Fix the value passed as processDefinition
Be sure we fetch the form variables

* * Fixed failing unit test

* * Rename formId to formKey.

* * Reverted form Changes

* * Fixed failing unit test

* Fix form representation structure

* Refactor form models

* Change tslint config

* Fix lint

* Refactor form models

* Remove duplicated export

* improve variable names

* Update form mock
This commit is contained in:
Maurizio Vitale 2019-06-12 12:50:10 +01:00 committed by Eugenio Romano
parent 051e8df091
commit 63f00e21cf
20 changed files with 916 additions and 924 deletions

View File

@ -54,8 +54,7 @@ export class FormCloudDemoComponent implements OnInit, OnDestroy {
}
ngOnInit() {
const formDefinitionJSON = this.automationService.forms.getFormCloudDefinition();
this.formConfig = JSON.stringify(formDefinitionJSON);
this.formConfig = JSON.stringify(this.automationService.forms.getFormCloudDefinition());
this.parseForm();
}

View File

@ -62,8 +62,7 @@ export class FormComponent implements OnInit, OnDestroy {
}
ngOnInit() {
const formDefinitionJSON: any = this.automationService.forms.getFormDefinition();
this.formConfig = JSON.stringify(formDefinitionJSON);
this.formConfig = JSON.stringify(this.automationService.forms.getFormDefinition());
this.parseForm();
}

View File

@ -30,7 +30,6 @@ export abstract class FormBaseModel {
static START_PROCESS_OUTCOME: string = '$startProcess';
json: any;
isValid: boolean;
values: FormValues = {};
tabs: TabModel[] = [];
@ -41,6 +40,8 @@ export abstract class FormBaseModel {
readOnly: boolean = false;
taskName;
isValid: boolean = true;
hasTabs(): boolean {
return this.tabs && this.tabs.length > 0;
}
@ -77,8 +78,11 @@ export abstract class FormBaseModel {
return formFieldModel;
}
markAsInvalid() {
this.isValid = false;
}
abstract validateForm();
abstract validateField(field: FormFieldModel);
abstract onFormFieldChanged(field: FormFieldModel);
abstract markAsInvalid();
}

View File

@ -68,7 +68,7 @@ export class FormFieldModel extends FormWidgetModel {
visibilityCondition: WidgetVisibilityModel = null;
enableFractions: boolean = false;
currency: string = null;
dateDisplayFormat: string = this.dateDisplayFormat || this.defaultDateFormat;
dateDisplayFormat: string = this.defaultDateFormat;
// container model members
numberOfColumns: number = 1;

View File

@ -35,7 +35,10 @@ describe('FormModel', () => {
});
it('should store original json', () => {
const json = {};
const json = {
id: '<id>',
name: '<name>'
};
const form = new FormModel(json);
expect(form.json).toBe(json);
});

View File

@ -43,11 +43,6 @@ export class FormModel extends FormBaseModel {
readonly taskId: string;
readonly taskName: string = FormModel.UNSET_TASK_NAME;
processDefinitionId: string;
private _isValid: boolean = true;
get isValid(): boolean {
return this._isValid;
}
customFieldTemplates: FormFieldTemplates = {};
fieldValidators: FormFieldValidator[] = [...FORM_FIELD_VALIDATORS];
@ -55,33 +50,33 @@ export class FormModel extends FormBaseModel {
processVariables: any;
constructor(json?: any, formValues?: FormValues, readOnly: boolean = false, protected formService?: FormService) {
constructor(formRepresentationJSON?: any, formValues?: FormValues, readOnly: boolean = false, protected formService?: FormService) {
super();
this.readOnly = readOnly;
if (json) {
this.json = json;
if (formRepresentationJSON) {
this.json = formRepresentationJSON;
this.id = json.id;
this.name = json.name;
this.taskId = json.taskId;
this.taskName = json.taskName || json.name || FormModel.UNSET_TASK_NAME;
this.processDefinitionId = json.processDefinitionId;
this.customFieldTemplates = json.customFieldTemplates || {};
this.selectedOutcome = json.selectedOutcome || {};
this.className = json.className || '';
this.id = formRepresentationJSON.id;
this.name = formRepresentationJSON.name;
this.taskId = formRepresentationJSON.taskId;
this.taskName = formRepresentationJSON.taskName || formRepresentationJSON.name || FormModel.UNSET_TASK_NAME;
this.processDefinitionId = formRepresentationJSON.processDefinitionId;
this.customFieldTemplates = formRepresentationJSON.customFieldTemplates || {};
this.selectedOutcome = formRepresentationJSON.selectedOutcome || {};
this.className = formRepresentationJSON.className || '';
const tabCache: FormWidgetModelCache<TabModel> = {};
this.processVariables = json.processVariables;
this.processVariables = formRepresentationJSON.processVariables;
this.tabs = (json.tabs || []).map((t) => {
this.tabs = (formRepresentationJSON.tabs || []).map((t) => {
const model = new TabModel(this, t);
tabCache[model.id] = model;
return model;
});
this.fields = this.parseRootFields(json);
this.fields = this.parseRootFields(formRepresentationJSON);
if (formValues) {
this.loadData(formValues);
@ -97,7 +92,7 @@ export class FormModel extends FormBaseModel {
}
}
if (json.fields) {
if (formRepresentationJSON.fields) {
const saveOutcome = new FormOutcomeModel(this, {
id: FormModel.SAVE_OUTCOME,
name: 'SAVE',
@ -114,7 +109,7 @@ export class FormModel extends FormBaseModel {
isSystem: true
});
const customOutcomes = (json.outcomes || []).map((obj) => new FormOutcomeModel(this, obj));
const customOutcomes = (formRepresentationJSON.outcomes || []).map((obj) => new FormOutcomeModel(this, obj));
this.outcomes = [saveOutcome].concat(
customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome]
@ -132,10 +127,6 @@ export class FormModel extends FormBaseModel {
}
}
markAsInvalid() {
this._isValid = false;
}
/**
* Validates entire form and all form fields.
*
@ -153,10 +144,10 @@ export class FormModel extends FormBaseModel {
}
}
this._isValid = errorsField.length > 0 ? false : true;
this.isValid = errorsField.length > 0 ? false : true;
if (this.formService) {
validateFormEvent.isValid = this._isValid;
validateFormEvent.isValid = this.isValid;
validateFormEvent.errorsField = errorsField;
this.formService.validateForm.next(validateFormEvent);
}
@ -181,7 +172,7 @@ export class FormModel extends FormBaseModel {
}
if (!validateFieldEvent.isValid) {
this._isValid = false;
this.markAsInvalid();
return;
}
@ -190,7 +181,7 @@ export class FormModel extends FormBaseModel {
}
if (!field.validate()) {
this._isValid = false;
this.markAsInvalid();
}
this.validateForm();

View File

@ -16,6 +16,7 @@
*/
export * from './components/form-base.component';
export * from './components/form-base.model';
export * from './components/form-list.component';
export * from './components/widgets/content/content.widget';
export * from './components/form-renderer.component';

View File

@ -215,14 +215,7 @@ export class WidgetVisibilityService {
}
private getFormVariables(form: FormModel): any[] {
let variables;
if (form.json.formRepresentation) {
variables = form.json.formRepresentation.formDefinition.variables;
} else {
variables = form.json.variables;
}
return variables;
return form.json.variables;
}
private getProcessVariableValue(name: string, processVarList: TaskProcessVariableModel[]): string {

View File

@ -32,7 +32,7 @@
* limitations under the License.
*/
export class DemoForms {
export class DemoForm {
easyForm = {
'id': 1001,

View File

@ -20,13 +20,14 @@ import { AppConfigService } from '../app-config/app-config.service';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { StorageService } from './storage.service';
import { UserPreferencesService } from './user-preferences.service';
import { DemoForms } from '../mock/form/demo-form.mock';
import { DemoForm } from '../mock/form/demo-form.mock';
@Injectable({
providedIn: 'root'
})
export class CoreAutomationService {
forms = new DemoForms();
public forms = new DemoForm();
constructor(private appConfigService: AppConfigService,
private alfrescoApiService: AlfrescoApiService,

View File

@ -19,13 +19,16 @@ import { SimpleChange, DebugElement, CUSTOM_ELEMENTS_SCHEMA, Component } from '@
import { By } from '@angular/platform-browser';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Observable, of, throwError } from 'rxjs';
import { FormFieldModel, FormFieldTypes, FormService, FormOutcomeEvent, FormOutcomeModel, LogService, WidgetVisibilityService,
setupTestBed, AppConfigService, FormRenderingService } from '@alfresco/adf-core';
import {
FormFieldModel, FormFieldTypes, FormService, FormOutcomeEvent, FormOutcomeModel, LogService, WidgetVisibilityService,
setupTestBed, AppConfigService, FormRenderingService
} from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { FormCloudService } from '../services/form-cloud.service';
import { FormCloudComponent } from './form-cloud.component';
import { FormCloud } from '../models/form-cloud.model';
import { cloudFormMock } from '../mocks/cloud-form.mock';
import { FormCloudRepresentation } from '../models/form-cloud-representation.model';
describe('FormCloudComponent', () => {
@ -120,7 +123,7 @@ describe('FormCloudComponent', () => {
});
it('should show [custom-outcome] button with readOnly form and selected custom-outcome', () => {
const formModel = new FormCloud({formRepresentation: {formDefinition: {selectedOutcome: 'custom-outcome'}}});
const formModel = new FormCloud({ selectedOutcome: 'custom-outcome' });
formModel.readOnly = true;
formComponent.form = formModel;
let outcome = new FormOutcomeModel(<any> formModel, { id: '$customoutome', name: 'custom-outcome' });
@ -156,7 +159,7 @@ describe('FormCloudComponent', () => {
it('should get task variables if a task form is rendered', () => {
spyOn(formCloudService, 'getTaskForm').and.callFake((currentTaskId) => {
return new Observable((observer) => {
observer.next({ formRepresentation: { taskId: currentTaskId }});
observer.next({ formRepresentation: { taskId: currentTaskId } });
observer.complete();
});
});
@ -164,7 +167,7 @@ describe('FormCloudComponent', () => {
spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({}));
spyOn(formCloudService, 'getTask').and.callFake((currentTaskId) => {
return new Observable((observer) => {
observer.next({ formRepresentation: { taskId: currentTaskId }});
observer.next({ formRepresentation: { taskId: currentTaskId } });
observer.complete();
});
});
@ -210,7 +213,7 @@ describe('FormCloudComponent', () => {
});
it('should refresh visibility when the form is loaded', () => {
spyOn(formCloudService, 'getForm').and.returnValue(of({formRepresentation: {formDefinition: {}}}));
spyOn(formCloudService, 'getForm').and.returnValue(of({ formRepresentation: {} }));
const formId = '123';
const appName = 'test-app';
@ -388,7 +391,7 @@ describe('FormCloudComponent', () => {
spyOn(formCloudService, 'getTask').and.returnValue(of({}));
spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({}));
spyOn(formCloudService, 'getTaskForm').and.returnValue(of({formRepresentation: {taskId: taskId, formDefinition: {selectedOutcome: 'custom-outcome'}}}));
spyOn(formCloudService, 'getTaskForm').and.returnValue(of({ taskId: taskId, selectedOutcome: 'custom-outcome' }));
formComponent.formLoaded.subscribe(() => {
expect(formCloudService.getTaskForm).toHaveBeenCalledWith(appName, taskId);
@ -421,7 +424,7 @@ describe('FormCloudComponent', () => {
it('should fetch and parse form definition by id', (done) => {
spyOn(formCloudService, 'getForm').and.callFake((currentAppName, currentFormId) => {
return new Observable((observer) => {
observer.next({ formRepresentation: {id: currentFormId, formDefinition: {}}});
observer.next({ id: currentFormId });
observer.complete();
});
});
@ -469,16 +472,12 @@ describe('FormCloudComponent', () => {
const processInstanceId = '333-444';
const formModel = new FormCloud({
formRepresentation: {
id: '23',
taskId: taskId,
formDefinition: {
fields: [
{ id: 'field1' },
{ id: 'field2' }
]
}
}
id: '23',
taskId: taskId,
fields: [
{ id: 'field1' },
{ id: 'field2' }
]
});
formComponent.form = formModel;
formComponent.taskId = taskId;
@ -500,16 +499,12 @@ describe('FormCloudComponent', () => {
const taskId = '123-223';
const appName = 'test-app';
const formModel = new FormCloud({
formRepresentation: {
id: '23',
taskId: taskId,
formDefinition: {
fields: [
{ id: 'field1' },
{ id: 'field2' }
]
}
}
id: '23',
taskId: taskId,
fields: [
{ id: 'field1' },
{ id: 'field2' }
]
});
formComponent.form = formModel;
formComponent.taskId = taskId;
@ -572,16 +567,12 @@ describe('FormCloudComponent', () => {
const processInstanceId = '333-444';
const formModel = new FormCloud({
formRepresentation: {
id: '23',
taskId: taskId,
formDefinition: {
fields: [
{ id: 'field1' },
{ id: 'field2' }
]
}
}
id: '23',
taskId: taskId,
fields: [
{ id: 'field1' },
{ id: 'field2' }
]
});
formComponent.form = formModel;
@ -600,14 +591,10 @@ describe('FormCloudComponent', () => {
it('should parse form from json', () => {
const form = formComponent.parseForm({
formRepresentation: {
id: '1',
formDefinition: {
fields: [
{ id: 'field1', type: FormFieldTypes.CONTAINER }
]
}
}
id: '1',
fields: [
{ id: 'field1', type: FormFieldTypes.CONTAINER }
]
});
expect(form).toBeDefined();
@ -619,7 +606,7 @@ describe('FormCloudComponent', () => {
it('should provide outcomes for form definition', () => {
spyOn(formComponent, 'getFormDefinitionOutcomes').and.callThrough();
const form = formComponent.parseForm({ formRepresentation: { id: 1, formDefinition: {}}});
const form = formComponent.parseForm({ id: '1' });
expect(formComponent.getFormDefinitionOutcomes).toHaveBeenCalledWith(form);
});
@ -754,6 +741,7 @@ describe('FormCloudComponent', () => {
it('should refresh form values when data is changed', (done) => {
formComponent.form = new FormCloud(JSON.parse(JSON.stringify(cloudFormMock)));
formComponent.formCloudRepresentationJSON = new FormCloudRepresentation(JSON.parse(JSON.stringify(cloudFormMock)));
let formFields = formComponent.form.getFormFields();
let labelField = formFields.find((field) => field.id === 'text1');
@ -761,12 +749,12 @@ describe('FormCloudComponent', () => {
expect(labelField.value).toBeNull();
expect(radioField.value).toBeUndefined();
const formValues: any[] = [{name: 'text1', value: 'test'}, {name: 'number1', value: 99}];
const formValues: any[] = [{ name: 'text1', value: 'test' }, { name: 'number1', value: 99 }];
const change = new SimpleChange(null, formValues, false);
formComponent.data = formValues;
formComponent.formLoaded.subscribe( (form) => {
formComponent.formLoaded.subscribe((form) => {
formFields = form.getFormFields();
labelField = formFields.find((field) => field.id === 'text1');
radioField = formFields.find((field) => field.id === 'number1');
@ -782,10 +770,11 @@ describe('FormCloudComponent', () => {
it('should refresh radio buttons value when id is given to data', () => {
formComponent.form = new FormCloud(JSON.parse(JSON.stringify(cloudFormMock)));
formComponent.formCloudRepresentationJSON = new FormCloudRepresentation(JSON.parse(JSON.stringify(cloudFormMock)));
let formFields = formComponent.form.getFormFields();
let radioFieldById = formFields.find((field) => field.id === 'radiobuttons1');
const formValues: any[] = [{name: 'radiobuttons1', value: 'option_2'}];
const formValues: any[] = [{ name: 'radiobuttons1', value: 'option_2' }];
const change = new SimpleChange(null, formValues, false);
formComponent.data = formValues;
formComponent.ngOnChanges({ 'data': change });
@ -797,7 +786,7 @@ describe('FormCloudComponent', () => {
});
@Component({
selector: 'adf-form-cloud-with-custom-outcomes',
selector: 'adf-cloud-form-with-custom-outcomes',
template: `
<adf-cloud-form #adfCloudForm>
<adf-cloud-form-custom-outcomes>
@ -813,7 +802,7 @@ describe('FormCloudComponent', () => {
class FormCloudWithCustomOutComesComponent {
onButtonClick() {}
onButtonClick() { }
}
describe('FormCloudWithCustomOutComesComponent', () => {

View File

@ -92,6 +92,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
protected subscriptions: Subscription[] = [];
nodeId: string;
formCloudRepresentationJSON: any;
protected onDestroy$ = new Subject<boolean>();
@ -181,7 +182,8 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
.subscribe(
(data) => {
this.data = data[1];
const parsedForm = this.parseForm(data[0]);
this.formCloudRepresentationJSON = data[0];
const parsedForm = this.parseForm(this.formCloudRepresentationJSON);
this.visibilityService.refreshVisibility(<any> parsedForm);
parsedForm.validateForm();
this.form = parsedForm;
@ -268,10 +270,10 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
}
}
parseForm(json: any): FormCloud {
if (json) {
const form = new FormCloud(json, this.data, this.readOnly, this.formCloudService);
if (!json.formRepresentation.formDefinition || !json.formRepresentation.formDefinition.fields) {
parseForm(formCloudRepresentationJSON: any): FormCloud {
if (formCloudRepresentationJSON) {
const form = new FormCloud(formCloudRepresentationJSON, this.data, this.readOnly, this.formCloudService);
if (!form || !form.fields.length) {
form.outcomes = this.getFormDefinitionOutcomes(form);
}
if (this.fieldValidators && this.fieldValidators.length > 0) {
@ -299,7 +301,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
}
private refreshFormData() {
this.form = this.parseForm(this.form.json);
this.form = this.parseForm(this.formCloudRepresentationJSON);
this.onFormLoaded(this.form);
this.onFormDataRefreshed(this.form);
}

View File

@ -0,0 +1,51 @@
/*!
* @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.
*/
export class FormCloudRepresentation {
id?: string;
name?: string;
description?: string;
version?: number;
tabs?: any[];
fields?: any[];
outcomes?: any[];
metadata?: any;
variables?: any[];
taskId?: string;
taskName?: string;
processDefinitionId?: string;
processInstanceId?: string;
selectedOutcome?: string;
constructor(obj?: any) {
this.id = obj.id || null;
this.name = obj.name || null;
this.description = obj.description || null;
this.version = obj.version || null;
this.tabs = obj.tabs || null;
this.fields = obj.fields || null;
this.outcomes = obj.outcomes || null;
this.metadata = obj.metadata || null;
this.variables = obj.variables || null;
this.taskId = obj.taskId || null;
this.taskName = obj.taskName || null;
this.processDefinitionId = obj.processDefinitionId || null;
this.processInstanceId = obj.processInstanceId || null;
this.selectedOutcome = obj.selectedOutcome || null;
}
}

View File

@ -18,6 +18,7 @@
import { FormCloudService } from '../services/form-cloud.service';
import { FormCloud } from './form-cloud.model';
import { TabModel, FormFieldModel, ContainerModel, FormOutcomeModel, FormFieldTypes, AppConfigService } from '@alfresco/adf-core';
import { FormCloudRepresentation } from './form-cloud-representation.model';
describe('FormCloud', () => {
@ -28,33 +29,33 @@ describe('FormCloud', () => {
});
it('should store original json', () => {
const json = {formRepresentation: {formDefinition: {}}};
const form = new FormCloud(json);
expect(form.json).toBe(json);
const formRepresentation = {fields: []};
const form = new FormCloud(formRepresentation);
expect(form.json).toEqual(formRepresentation);
});
it('should setup properties with json', () => {
const json = {formRepresentation: {
const formRepresentation: FormCloudRepresentation = {
id: '<id>',
name: '<name>',
taskId: '<task-id>',
taskName: '<task-name>'
}};
const form = new FormCloud(json);
};
const form = new FormCloud(formRepresentation);
Object.keys(json).forEach((key) => {
Object.keys(formRepresentation).forEach((key) => {
expect(form[key]).toEqual(form[key]);
});
});
it('should take form name when task name is missing', () => {
const json = {formRepresentation: {
const formRepresentation = {
id: '<id>',
name: '<name>',
formDefinition: {}
}};
const form = new FormCloud(json);
expect(form.taskName).toBe(json.formRepresentation.name);
};
const form = new FormCloud(formRepresentation);
expect(form.taskName).toBe(formRepresentation.name);
});
it('should set readonly state from params', () => {
@ -103,21 +104,21 @@ describe('FormCloud', () => {
});
it('should parse tabs', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
tabs: [
{ id: 'tab1' },
{ id: 'tab2' }
]
}}};
};
const form = new FormCloud(json);
const form = new FormCloud(formRepresentation);
expect(form.tabs.length).toBe(2);
expect(form.tabs[0].id).toBe('tab1');
expect(form.tabs[1].id).toBe('tab2');
});
it('should parse fields', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
fields: [
{
id: 'field1',
@ -128,26 +129,26 @@ describe('FormCloud', () => {
type: FormFieldTypes.CONTAINER
}
]
}}};
};
const form = new FormCloud(json);
const form = new FormCloud(formRepresentation);
expect(form.fields.length).toBe(2);
expect(form.fields[0].id).toBe('field1');
expect(form.fields[1].id).toBe('field2');
});
it('should convert missing fields to empty collection', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
fields: null
}}};
};
const form = new FormCloud(json);
const form = new FormCloud(formRepresentation);
expect(form.fields).toBeDefined();
expect(form.fields.length).toBe(0);
});
it('should put fields into corresponding tabs', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
tabs: [
{ id: 'tab1' },
{ id: 'tab2' }
@ -158,9 +159,9 @@ describe('FormCloud', () => {
{ id: 'field3', tab: 'tab1', type: FormFieldTypes.DYNAMIC_TABLE },
{ id: 'field4', tab: 'missing-tab', type: FormFieldTypes.DYNAMIC_TABLE }
]
}}};
};
const form = new FormCloud(json);
const form = new FormCloud(formRepresentation);
expect(form.tabs.length).toBe(2);
expect(form.fields.length).toBe(4);
@ -175,13 +176,13 @@ describe('FormCloud', () => {
});
it('should create standard form outcomes', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
fields: [
{ id: 'container1' }
]
}}};
};
const form = new FormCloud(json);
const form = new FormCloud(formRepresentation);
expect(form.outcomes.length).toBe(3);
expect(form.outcomes[0].id).toBe(FormCloud.SAVE_OUTCOME);
@ -195,24 +196,24 @@ describe('FormCloud', () => {
});
it('should create outcomes only when fields available', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
fields: null
}}};
const form = new FormCloud(json);
};
const form = new FormCloud(formRepresentation);
expect(form.outcomes.length).toBe(0);
});
it('should use custom form outcomes', () => {
const json = {formRepresentation: {formDefinition: {
const formRepresentation = {
fields: [
{ id: 'container1' }
]},
],
outcomes: [
{ id: 'custom-1', name: 'custom 1' }
]
}};
};
const form = new FormCloud(json);
const form = new FormCloud(formRepresentation);
expect(form.outcomes.length).toBe(2);
expect(form.outcomes[0].id).toBe(FormCloud.SAVE_OUTCOME);

View File

@ -18,11 +18,11 @@
import {
TabModel, FormWidgetModel, FormOutcomeModel, FormValues,
FormWidgetModelCache, FormFieldModel, ContainerModel, FormFieldTypes,
ValidateFormFieldEvent, FormFieldValidator, FormFieldTemplates } from '@alfresco/adf-core';
ValidateFormFieldEvent, FormFieldValidator, FormFieldTemplates, FormBaseModel } from '@alfresco/adf-core';
import { FormCloudService } from '../services/form-cloud.service';
import { TaskVariableCloud } from './task-variable-cloud.model';
export class FormCloud {
export class FormCloud extends FormBaseModel {
static SAVE_OUTCOME: string = '$save';
static COMPLETE_OUTCOME: string = '$complete';
@ -34,14 +34,8 @@ export class FormCloud {
readonly name: string;
readonly taskId: string;
readonly taskName: string;
private _isValid: boolean = true;
get isValid(): boolean {
return this._isValid;
}
readonly selectedOutcome: string;
readonly json: any;
readOnly: boolean;
processDefinitionId: any;
@ -54,29 +48,28 @@ export class FormCloud {
customFieldTemplates: FormFieldTemplates = {};
fieldValidators: FormFieldValidator[] = [];
constructor(json?: any, formData?: TaskVariableCloud[], readOnly: boolean = false, protected formService?: FormCloudService) {
constructor(formCloudRepresentationJSON?: any, formData?: TaskVariableCloud[], readOnly: boolean = false, protected formService?: FormCloudService) {
super();
this.readOnly = readOnly;
if (json && json.formRepresentation && json.formRepresentation.formDefinition) {
this.json = json;
this.id = json.formRepresentation.id;
this.name = json.formRepresentation.name;
this.taskId = json.formRepresentation.taskId;
this.taskName = json.formRepresentation.taskName || json.formRepresentation.name;
this.processDefinitionId = json.formRepresentation.processDefinitionId;
this.customFieldTemplates = json.formRepresentation.formDefinition.customFieldTemplates || {};
this.selectedOutcome = json.formRepresentation.formDefinition.selectedOutcome || {};
this.className = json.formRepresentation.formDefinition.className || '';
if (formCloudRepresentationJSON) {
this.json = formCloudRepresentationJSON;
this.id = formCloudRepresentationJSON.id;
this.name = formCloudRepresentationJSON.name;
this.taskId = formCloudRepresentationJSON.taskId;
this.taskName = formCloudRepresentationJSON.taskName || formCloudRepresentationJSON.name;
this.processDefinitionId = formCloudRepresentationJSON.processDefinitionId;
this.selectedOutcome = formCloudRepresentationJSON.selectedOutcome || '';
const tabCache: FormWidgetModelCache<TabModel> = {};
this.tabs = (json.formRepresentation.formDefinition.tabs || []).map((t) => {
this.tabs = (formCloudRepresentationJSON.tabs || []).map((t) => {
const model = new TabModel(<any> this, t);
tabCache[model.id] = model;
return model;
});
this.fields = this.parseRootFields(json);
this.fields = this.parseRootFields(formCloudRepresentationJSON);
if (formData && formData.length > 0) {
this.loadData(formData);
@ -93,7 +86,7 @@ export class FormCloud {
}
}
if (json.formRepresentation.formDefinition.fields) {
if (formCloudRepresentationJSON.fields) {
const saveOutcome = new FormOutcomeModel(<any> this, {
id: FormCloud.SAVE_OUTCOME,
name: 'SAVE',
@ -110,7 +103,7 @@ export class FormCloud {
isSystem: true
});
const customOutcomes = (json.formRepresentation.outcomes || []).map((obj) => new FormOutcomeModel(<any> this, obj));
const customOutcomes = (formCloudRepresentationJSON.outcomes || []).map((obj) => new FormOutcomeModel(<any> this, obj));
this.outcomes = [saveOutcome].concat(
customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome]
@ -142,37 +135,10 @@ export class FormCloud {
return this.outcomes && this.outcomes.length > 0;
}
getFieldById(fieldId: string): FormFieldModel {
return this.getFormFields().find((field) => field.id === fieldId);
}
onFormFieldChanged(field: FormFieldModel) {
this.validateField(field);
}
getFormFields(): FormFieldModel[] {
const formFields: FormFieldModel[] = [];
for (let i = 0; i < this.fields.length; i++) {
const field = this.fields[i];
if (field instanceof ContainerModel) {
const container = <ContainerModel> field;
formFields.push(container.field);
container.field.columns.forEach((column) => {
formFields.push(...column.fields);
});
}
}
return formFields;
}
markAsInvalid() {
this._isValid = false;
}
validateForm() {
const errorsField: FormFieldModel[] = [];
@ -183,7 +149,7 @@ export class FormCloud {
}
}
this._isValid = errorsField.length > 0 ? false : true;
this.isValid = errorsField.length > 0 ? false : true;
}
/**
@ -200,7 +166,7 @@ export class FormCloud {
const validateFieldEvent = new ValidateFormFieldEvent(<any> this, field);
if (!validateFieldEvent.isValid) {
this._isValid = false;
this.isValid = false;
return;
}
@ -209,7 +175,7 @@ export class FormCloud {
}
if (!field.validate()) {
this._isValid = false;
this.isValid = false;
}
this.validateForm();
@ -219,10 +185,8 @@ export class FormCloud {
private parseRootFields(json: any): FormWidgetModel[] {
let fields = [];
if (json.formRepresentation.fields) {
fields = json.formRepresentation.fields;
} else if (json.formRepresentation.formDefinition && json.formRepresentation.formDefinition.fields) {
fields = json.formRepresentation.formDefinition.fields;
if (json.fields) {
fields = json.fields;
}
const formWidgetModel: FormWidgetModel[] = [];

View File

@ -150,15 +150,17 @@ describe('Form Cloud service', () => {
});
it('should fetch task form', (done) => {
it('should fetch task form flattened', (done) => {
spyOn(service, 'getTask').and.returnValue(of(responseBody.entry));
spyOn(service, 'getForm').and.returnValue(of({ formRepresentation: { name: 'task-form' } }));
spyOn(service, 'getForm').and.returnValue(of({
formRepresentation: {name: 'task-form', formDefinition: {} }
}));
service.getTaskForm(appName, taskId).subscribe((result) => {
expect(result).toBeDefined();
expect(result.formRepresentation.name).toBe('task-form');
expect(result.formRepresentation.taskId).toBe(responseBody.entry.id);
expect(result.formRepresentation.taskName).toBe(responseBody.entry.name);
expect(result.name).toBe('task-form');
expect(result.taskId).toBe(responseBody.entry.id);
expect(result.taskName).toBe(responseBody.entry.name);
done();
});

View File

@ -55,11 +55,13 @@ export class FormCloudService extends BaseCloudService {
switchMap((task: TaskDetailsCloudModel) => {
return this.getForm(appName, task.formKey).pipe(
map((form: any) => {
form.formRepresentation.taskId = task.id;
form.formRepresentation.taskName = task.name;
form.formRepresentation.processDefinitionId = task.processDefinitionId;
form.formRepresentation.processInstanceId = task.processInstanceId;
return form;
const flattenForm = {...form.formRepresentation, ...form.formRepresentation.formDefinition};
delete flattenForm.formDefinition;
flattenForm.taskId = task.id;
flattenForm.taskName = task.name;
flattenForm.processDefinitionId = task.processDefinitionId;
flattenForm.processInstanceId = task.processInstanceId;
return flattenForm;
})
);
})
@ -258,7 +260,10 @@ export class FormCloudService extends BaseCloudService {
*/
parseForm(json: any, data?: TaskVariableCloud[], readOnly: boolean = false): FormCloud {
if (json) {
const form = new FormCloud(json, data, readOnly, this);
const flattenForm = {...json.formRepresentation, ...json.formRepresentation.formDefinition};
delete flattenForm.formDefinition;
const form = new FormCloud(flattenForm, data, readOnly, this);
if (!json.fields) {
form.outcomes = [
new FormOutcomeModel(<any> form, {

View File

@ -81,65 +81,61 @@ export let fakeProcessPayload = new ProcessPayloadCloud({
});
export let fakeStartForm = {
'formRepresentation': {
'id': 'form-a5d50817-5183-4850-802d-17af54b2632f',
'name': 'simpleform',
'description': '',
'version': 0,
'formDefinition': {
'tabs': [],
'fields': [
{
'id': 'form-a5d50817-5183-4850-802d-17af54b2632f',
'name': 'simpleform',
'description': '',
'version': 0,
'tabs': [],
'fields': [
{
'type': 'container',
'id': '5a6b24c1-db2b-45e9-9aff-142395433d23',
'name': 'Label',
'tab': null,
'fields': {
'1': [
{
'type': 'text',
'id': 'firstName',
'name': 'firstName',
'colspan': 1,
'params': {
'existingColspan': 1,
'maxColspan': 2
},
'visibilityCondition': null,
'placeholder': null,
'value': null,
'required': false,
'minLength': 0,
'maxLength': 0,
'regexPattern': null
}
],
'2': [
{
'type': 'text',
'id': 'lastName',
'name': 'lastName',
'colspan': 1,
'params': {
'existingColspan': 1,
'maxColspan': 2
},
'visibilityCondition': null,
'placeholder': null,
'value': null,
'required': false,
'minLength': 0,
'maxLength': 0,
'regexPattern': null
}
]
'1': [
{
'type': 'text',
'id': 'firstName',
'name': 'firstName',
'colspan': 1,
'params': {
'existingColspan': 1,
'maxColspan': 2
},
'visibilityCondition': null,
'placeholder': null,
'value': null,
'required': false,
'minLength': 0,
'maxLength': 0,
'regexPattern': null
}
],
'2': [
{
'type': 'text',
'id': 'lastName',
'name': 'lastName',
'colspan': 1,
'params': {
'existingColspan': 1,
'maxColspan': 2
},
'visibilityCondition': null,
'placeholder': null,
'value': null,
'required': false,
'minLength': 0,
'maxLength': 0,
'regexPattern': null
}
]
},
'numberOfColumns': 2
}
],
'outcomes': [],
'metadata': {},
'variables': []
}
}
};
}
],
'outcomes': [],
'metadata': {},
'variables': []
};

View File

@ -282,10 +282,10 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
this.error.emit(err);
}
parseForm(json: any): FormModel {
if (json) {
const form = new FormModel(json, this.data, this.readOnly, this.formService);
if (!json.fields) {
parseForm(formRepresentationJSON: any): FormModel {
if (formRepresentationJSON) {
const form = new FormModel(formRepresentationJSON, this.data, this.readOnly, this.formService);
if (!formRepresentationJSON.fields) {
form.outcomes = this.getFormDefinitionOutcomes(form);
}
if (this.fieldValidators && this.fieldValidators.length > 0) {