diff --git a/demo-shell/src/app/components/app-layout/cloud/form-demo/cloud-form-demo.component.ts b/demo-shell/src/app/components/app-layout/cloud/form-demo/cloud-form-demo.component.ts index d875699933..e1e5c281fe 100644 --- a/demo-shell/src/app/components/app-layout/cloud/form-demo/cloud-form-demo.component.ts +++ b/demo-shell/src/app/components/app-layout/cloud/form-demo/cloud-form-demo.component.ts @@ -16,8 +16,8 @@ */ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { FormFieldModel, NotificationService, FormRenderingService, CoreAutomationService } from '@alfresco/adf-core'; -import { FormCloud, FormCloudService, UploadCloudWidgetComponent } from '@alfresco/adf-process-services-cloud'; +import { FormFieldModel, NotificationService, FormRenderingService, CoreAutomationService, FormModel } from '@alfresco/adf-core'; +import { FormCloudService, UploadCloudWidgetComponent } from '@alfresco/adf-process-services-cloud'; import { Subscription } from 'rxjs'; @Component({ @@ -26,7 +26,7 @@ import { Subscription } from 'rxjs'; }) export class FormCloudDemoComponent implements OnInit, OnDestroy { - form: FormCloud; + form: FormModel; errorFields: FormFieldModel[] = []; formConfig: string; editor: any; diff --git a/lib/core/form/components/form-base.component.ts b/lib/core/form/components/form-base.component.ts index c42fc7c50b..048d4e23ac 100644 --- a/lib/core/form/components/form-base.component.ts +++ b/lib/core/form/components/form-base.component.ts @@ -15,8 +15,7 @@ * limitations under the License. */ -import { FormBaseModel } from './form-base.model'; -import { FormOutcomeModel, FormFieldValidator, FormFieldModel, FormOutcomeEvent } from './widgets'; +import { FormOutcomeModel, FormFieldValidator, FormFieldModel, FormOutcomeEvent, FormModel } from './widgets'; import { EventEmitter, Input, Output } from '@angular/core'; export abstract class FormBaseComponent { @@ -92,7 +91,7 @@ export abstract class FormBaseComponent { @Output() error: EventEmitter = new EventEmitter(); - form: FormBaseModel; + form: FormModel; getParsedFormDefinition(): FormBaseComponent { return this; @@ -208,7 +207,7 @@ export abstract class FormBaseComponent { abstract completeTaskForm(outcome?: string); - protected abstract onTaskSaved(form: FormBaseModel); + protected abstract onTaskSaved(form: FormModel); protected abstract storeFormAsMetadata(); diff --git a/lib/core/form/components/form-base.model.ts b/lib/core/form/components/form-base.model.ts deleted file mode 100644 index aefe3ee232..0000000000 --- a/lib/core/form/components/form-base.model.ts +++ /dev/null @@ -1,88 +0,0 @@ -/*! - * @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. - */ - -import { FormValues } from './widgets/core/form-values'; -import { TabModel } from './widgets/core/tab.model'; -import { FormWidgetModel } from './widgets/core/form-widget.model'; -import { FormOutcomeModel } from './widgets/core/form-outcome.model'; -import { FormFieldModel } from './widgets/core/form-field.model'; -import { ContainerModel } from './widgets/core/container.model'; - -export abstract class FormBaseModel { - - static UNSET_TASK_NAME: string = 'Nameless task'; - static SAVE_OUTCOME: string = '$save'; - static COMPLETE_OUTCOME: string = '$complete'; - static START_PROCESS_OUTCOME: string = '$startProcess'; - - json: any; - - values: FormValues = {}; - tabs: TabModel[] = []; - fields: FormWidgetModel[] = []; - outcomes: FormOutcomeModel[] = []; - - className: string; - readOnly: boolean = false; - taskName; - - isValid: boolean = true; - - hasTabs(): boolean { - return this.tabs && this.tabs.length > 0; - } - - hasFields(): boolean { - return this.fields && this.fields.length > 0; - } - - hasOutcomes(): boolean { - return this.outcomes && this.outcomes.length > 0; - } - - getFieldById(fieldId: string): FormFieldModel { - return this.getFormFields().find((field) => field.id === fieldId); - } - - // TODO: consider evaluating and caching once the form is loaded - getFormFields(): FormFieldModel[] { - const formFieldModel: FormFieldModel[] = []; - - for (let i = 0; i < this.fields.length; i++) { - const field = this.fields[i]; - - if (field instanceof ContainerModel) { - const container = field; - formFieldModel.push(container.field); - - container.field.columns.forEach((column) => { - formFieldModel.push(...column.fields); - }); - } - } - - return formFieldModel; - } - - markAsInvalid() { - this.isValid = false; - } - - abstract validateForm(); - abstract validateField(field: FormFieldModel); - abstract onFormFieldChanged(field: FormFieldModel); -} diff --git a/lib/core/form/components/form-renderer.component.ts b/lib/core/form/components/form-renderer.component.ts index 46c340e9f7..1deb4323fe 100644 --- a/lib/core/form/components/form-renderer.component.ts +++ b/lib/core/form/components/form-renderer.component.ts @@ -16,7 +16,7 @@ */ import { Component, ViewEncapsulation, Input } from '@angular/core'; -import { FormBaseModel } from './form-base.model'; +import { FormModel } from './widgets/core/form.model'; @Component({ selector: 'adf-form-renderer', @@ -31,7 +31,7 @@ export class FormRendererComponent { showDebugButton: boolean = false; @Input() - formDefinition: FormBaseModel; + formDefinition: FormModel; debugMode: boolean; diff --git a/lib/core/form/components/widgets/core/form.model.ts b/lib/core/form/components/widgets/core/form.model.ts index 59bf9a8319..f4396b0fe8 100644 --- a/lib/core/form/components/widgets/core/form.model.ts +++ b/lib/core/form/components/widgets/core/form.model.ts @@ -15,71 +15,98 @@ * limitations under the License. */ -/* tslint:disable:component-selector */ - import { FormFieldEvent } from './../../../events/form-field.event'; import { ValidateFormFieldEvent } from './../../../events/validate-form-field.event'; import { ValidateFormEvent } from './../../../events/validate-form.event'; import { FormService } from './../../../services/form.service'; import { ContainerModel } from './container.model'; -import { FormFieldTemplates } from './form-field-templates'; import { FormFieldTypes } from './form-field-types'; import { FormFieldModel } from './form-field.model'; -import { FormOutcomeModel } from './form-outcome.model'; import { FormValues } from './form-values'; import { FormWidgetModel, FormWidgetModelCache } from './form-widget.model'; import { TabModel } from './tab.model'; -import { - FORM_FIELD_VALIDATORS, - FormFieldValidator -} from './form-field-validator'; -import { FormBaseModel } from '../../form-base.model'; import { FormVariableModel } from './form-variable.model'; import { ProcessVariableModel } from './process-variable.model'; +import { FormOutcomeModel } from './form-outcome.model'; +import { FormFieldValidator, FORM_FIELD_VALIDATORS } from './form-field-validator'; +import { FormFieldTemplates } from './form-field-templates'; -export class FormModel extends FormBaseModel { +export interface FormRepresentationModel { + [key: string]: any; - readonly id: number; + id?: string | number; + name?: string; + taskId?: string; + taskName?: string; + processDefinitionId?: string; + customFieldTemplates?: { + [key: string]: string + }; + selectedOutcome?: string; + fields?: any[]; + tabs?: any[]; + outcomes?: any[]; + formDefinition?: { + fields?: any[]; + }; +} + +export class FormModel { + + static UNSET_TASK_NAME: string = 'Nameless task'; + static SAVE_OUTCOME: string = '$save'; + static COMPLETE_OUTCOME: string = '$complete'; + static START_PROCESS_OUTCOME: string = '$startProcess'; + + readonly id: string | number; readonly name: string; readonly taskId: string; - readonly taskName: string = FormModel.UNSET_TASK_NAME; - processDefinitionId: string; - - customFieldTemplates: FormFieldTemplates = {}; - fieldValidators: FormFieldValidator[] = [...FORM_FIELD_VALIDATORS]; + readonly taskName = FormModel.UNSET_TASK_NAME; + readonly processDefinitionId: string; readonly selectedOutcome: string; + json: FormRepresentationModel; + nodeId: string; + contentHost: string; + values: FormValues = {}; + tabs: TabModel[] = []; + fields: FormWidgetModel[] = []; + outcomes: FormOutcomeModel[] = []; + fieldValidators: FormFieldValidator[] = [...FORM_FIELD_VALIDATORS]; + customFieldTemplates: FormFieldTemplates = {}; + + className: string; + readOnly = false; + isValid = true; processVariables: ProcessVariableModel[] = []; variables: FormVariableModel[] = []; - constructor(formRepresentationJSON?: any, formValues?: FormValues, readOnly: boolean = false, protected formService?: FormService) { - super(); + constructor(json?: FormRepresentationModel, formValues?: FormValues, readOnly: boolean = false, protected formService?: FormService) { this.readOnly = readOnly; + this.json = json; - if (formRepresentationJSON) { - this.json = formRepresentationJSON; - - 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 || ''; - this.variables = formRepresentationJSON.variables || []; - this.processVariables = formRepresentationJSON.processVariables || []; + if (json) { + 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.variables = json.variables || []; + this.processVariables = json.processVariables || []; const tabCache: FormWidgetModelCache = {}; - this.tabs = (formRepresentationJSON.tabs || []).map((t) => { - const model = new TabModel(this, t); + this.tabs = (json.tabs || []).map((tabJson) => { + const model = new TabModel(this, tabJson); tabCache[model.id] = model; return model; }); - this.fields = this.parseRootFields(formRepresentationJSON); + this.fields = this.parseRootFields(json); if (formValues) { this.loadData(formValues); @@ -95,29 +122,7 @@ export class FormModel extends FormBaseModel { } } - if (formRepresentationJSON.fields) { - const saveOutcome = new FormOutcomeModel(this, { - id: FormModel.SAVE_OUTCOME, - name: 'SAVE', - isSystem: true - }); - const completeOutcome = new FormOutcomeModel(this, { - id: FormModel.COMPLETE_OUTCOME, - name: 'COMPLETE', - isSystem: true - }); - const startProcessOutcome = new FormOutcomeModel(this, { - id: FormModel.START_PROCESS_OUTCOME, - name: 'START PROCESS', - isSystem: true - }); - - const customOutcomes = (formRepresentationJSON.outcomes || []).map((obj) => new FormOutcomeModel(this, obj)); - - this.outcomes = [saveOutcome].concat( - customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome] - ); - } + this.parseOutcomes(); } this.validateForm(); @@ -125,6 +130,7 @@ export class FormModel extends FormBaseModel { onFormFieldChanged(field: FormFieldModel) { this.validateField(field); + if (this.formService) { this.formService.formFieldValueChanged.next(new FormFieldEvent(this, field)); } @@ -223,8 +229,10 @@ export class FormModel extends FormBaseModel { // Typically used when form definition and form data coming from different sources private loadData(formValues: FormValues) { for (const field of this.getFormFields()) { - if (formValues[field.id]) { - field.json.value = formValues[field.id]; + const variableId = `variables.${field.name}`; + + if (formValues[variableId] || formValues[field.id]) { + field.json.value = formValues[variableId] || formValues[field.id]; field.value = field.parseValue(field.json); } } @@ -253,15 +261,8 @@ export class FormModel extends FormBaseModel { getFormVariableValue(identifier: string): any { const variable = this.getFormVariable(identifier); - if (variable) { - switch (variable.type) { - case 'date': - return `${variable.value}T00:00:00.000Z`; - case 'boolean': - return JSON.parse(variable.value); - default: - return variable.value; - } + if (variable && variable.hasOwnProperty('value')) { + return this.parseValue(variable.type, variable.value); } return undefined; @@ -280,15 +281,98 @@ export class FormModel extends FormBaseModel { ); if (variable) { - switch (variable.type) { - case 'boolean': - return JSON.parse(variable.value); - default: - return variable.value; - } + return this.parseValue(variable.type, variable.value); } } return undefined; } + + protected parseValue(type: string, value: any): any { + if (type && value) { + switch (type) { + case 'date': + return value + ? `${value}T00:00:00.000Z` + : undefined; + case 'boolean': + return typeof value === 'string' + ? JSON.parse(value) + : value; + default: + return value; + } + } + + return value; + } + + hasTabs(): boolean { + return this.tabs && this.tabs.length > 0; + } + + hasFields(): boolean { + return this.fields && this.fields.length > 0; + } + + hasOutcomes(): boolean { + return this.outcomes && this.outcomes.length > 0; + } + + getFieldById(fieldId: string): FormFieldModel { + return this.getFormFields().find((field) => field.id === fieldId); + } + + getFormFields(): FormFieldModel[] { + const formFieldModel: FormFieldModel[] = []; + + for (let i = 0; i < this.fields.length; i++) { + const field = this.fields[i]; + + if (field instanceof ContainerModel) { + const container = field; + formFieldModel.push(container.field); + + container.field.columns.forEach((column) => { + formFieldModel.push(...column.fields); + }); + } + } + + return formFieldModel; + } + + markAsInvalid(): void { + this.isValid = false; + } + + protected parseOutcomes() { + if (this.json.fields) { + const saveOutcome = new FormOutcomeModel( this, { + id: FormModel.SAVE_OUTCOME, + name: 'SAVE', + isSystem: true + }); + const completeOutcome = new FormOutcomeModel( this, { + id: FormModel.COMPLETE_OUTCOME, + name: 'COMPLETE', + isSystem: true + }); + const startProcessOutcome = new FormOutcomeModel( this, { + id: FormModel.START_PROCESS_OUTCOME, + name: 'START PROCESS', + isSystem: true + }); + + const customOutcomes = (this.json.outcomes || []).map( + (obj) => new FormOutcomeModel( this, obj) + ); + + this.outcomes = [saveOutcome].concat( + customOutcomes.length > 0 + ? customOutcomes + : [completeOutcome, startProcessOutcome] + ); + } + } } diff --git a/lib/core/form/components/widgets/core/group.model.ts b/lib/core/form/components/widgets/core/group.model.ts index efc1126ee8..64ac490c54 100644 --- a/lib/core/form/components/widgets/core/group.model.ts +++ b/lib/core/form/components/widgets/core/group.model.ts @@ -15,24 +15,10 @@ * limitations under the License. */ - /* tslint:disable:component-selector */ - -export class GroupModel { - - externalId: string; - groups: any; - id: string; - name: string; - status: string; - - constructor(json?: any) { - if (json) { - this.externalId = json.externalId; - this.groups = json.groups; - this.id = json.id; - this.name = json.name; - this.status = json.status; - } - } - +export interface GroupModel { + externalId?: string; + groups?: any; + id?: string; + name?: string; + status?: string; } diff --git a/lib/core/form/components/widgets/functional-group/functional-group.widget.spec.ts b/lib/core/form/components/widgets/functional-group/functional-group.widget.spec.ts index 2900bd9e4b..1e5afecd7e 100644 --- a/lib/core/form/components/widgets/functional-group/functional-group.widget.spec.ts +++ b/lib/core/form/components/widgets/functional-group/functional-group.widget.spec.ts @@ -36,7 +36,7 @@ describe('FunctionalGroupWidgetComponent', () => { }); it('should setup text from underlying field on init', () => { - const group = new GroupModel({ name: 'group-1'}); + const group: GroupModel = { name: 'group-1'}; widget.field.value = group; spyOn(formService, 'getWorkflowGroups').and.returnValue( @@ -81,7 +81,7 @@ describe('FunctionalGroupWidgetComponent', () => { }); it('should update values on item click', () => { - const item = new GroupModel({ name: 'group-1' }); + const item: GroupModel = { name: 'group-1' }; widget.onItemClick(item, null); expect(widget.field.value).toBe(item); @@ -96,8 +96,8 @@ describe('FunctionalGroupWidgetComponent', () => { it('should flush selected value', () => { const groups: GroupModel[] = [ - new GroupModel({ id: '1', name: 'group 1' }), - new GroupModel({ id: '2', name: 'group 2' }) + { id: '1', name: 'group 1' }, + { id: '2', name: 'group 2' } ]; widget.groups = groups; @@ -110,8 +110,8 @@ describe('FunctionalGroupWidgetComponent', () => { it('should be case insensitive when flushing value', () => { const groups: GroupModel[] = [ - new GroupModel({ id: '1', name: 'group 1' }), - new GroupModel({ id: '2', name: 'gRoUp 2' }) + { id: '1', name: 'group 1' }, + { id: '2', name: 'gRoUp 2' } ]; widget.groups = groups; @@ -123,10 +123,7 @@ describe('FunctionalGroupWidgetComponent', () => { }); it('should fetch groups and show popup on key up', () => { - const groups: GroupModel[] = [ - new GroupModel(), - new GroupModel() - ]; + const groups: GroupModel[] = [{}, {}]; spyOn(formService, 'getWorkflowGroups').and.returnValue( new Observable((observer) => { observer.next(groups); @@ -143,10 +140,7 @@ describe('FunctionalGroupWidgetComponent', () => { }); it('should fetch groups with a group filter', () => { - const groups: GroupModel[] = [ - new GroupModel(), - new GroupModel() - ]; + const groups: GroupModel[] = [{}, {}]; spyOn(formService, 'getWorkflowGroups').and.returnValue( new Observable((observer) => { observer.next(groups); diff --git a/lib/core/form/components/widgets/functional-group/functional-group.widget.ts b/lib/core/form/components/widgets/functional-group/functional-group.widget.ts index a0eb391c8c..10c15fa8d5 100644 --- a/lib/core/form/components/widgets/functional-group/functional-group.widget.ts +++ b/lib/core/form/components/widgets/functional-group/functional-group.widget.ts @@ -60,7 +60,7 @@ export class FunctionalGroupWidgetComponent extends WidgetComponent implements O if (this.value) { this.formService .getWorkflowGroups(this.value, this.groupId) - .subscribe((groupModel: GroupModel[]) => this.groups = groupModel || []); + .subscribe(groups => this.groups = groups || []); } } } @@ -69,10 +69,9 @@ export class FunctionalGroupWidgetComponent extends WidgetComponent implements O if (this.value && this.value.length >= this.minTermLength && this.oldValue !== this.value) { if (event.keyCode !== ESCAPE && event.keyCode !== ENTER) { this.oldValue = this.value; - this.formService.getWorkflowGroups(this.value, this.groupId) - .subscribe((group: GroupModel[]) => { - this.groups = group || []; - }); + this.formService + .getWorkflowGroups(this.value, this.groupId) + .subscribe(groups => this.groups = groups || []); } } } diff --git a/lib/core/form/public-api.ts b/lib/core/form/public-api.ts index f7052e2255..c977566a48 100644 --- a/lib/core/form/public-api.ts +++ b/lib/core/form/public-api.ts @@ -16,7 +16,6 @@ */ 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'; diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts index 1c30a10ceb..bda5b5e50e 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts @@ -21,12 +21,11 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testin import { Observable, of, throwError } from 'rxjs'; import { FormFieldModel, FormFieldTypes, FormService, FormOutcomeEvent, FormOutcomeModel, LogService, WidgetVisibilityService, - setupTestBed, AppConfigService, FormRenderingService + setupTestBed, AppConfigService, FormRenderingService, FormModel } 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, fakeCloudForm } from '../mocks/cloud-form.mock'; import { FormCloudRepresentation } from '../models/form-cloud-representation.model'; @@ -53,12 +52,12 @@ describe('FormCloudComponent', () => { it('should check form', () => { expect(formComponent.hasForm()).toBeFalsy(); - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); expect(formComponent.hasForm()).toBeTruthy(); }); it('should allow title if showTitle is true', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formComponent.form = formModel; expect(formComponent.showTitle).toBeTruthy(); @@ -67,7 +66,7 @@ describe('FormCloudComponent', () => { }); it('should not allow title if showTitle is false', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formComponent.form = formModel; formComponent.showTitle = false; @@ -84,14 +83,14 @@ describe('FormCloudComponent', () => { }); it('should enable custom outcome buttons', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formComponent.form = formModel; const outcome = new FormOutcomeModel( formModel, { id: 'action1', name: 'Action 1' }); expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy(); }); it('should allow controlling [complete] button visibility', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formComponent.form = formModel; const outcome = new FormOutcomeModel( formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION }); @@ -103,7 +102,7 @@ describe('FormCloudComponent', () => { }); it('should show only [complete] button with readOnly form ', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formModel.readOnly = true; formComponent.form = formModel; const outcome = new FormOutcomeModel( formModel, { id: '$complete', name: FormOutcomeModel.COMPLETE_ACTION }); @@ -113,7 +112,7 @@ describe('FormCloudComponent', () => { }); it('should not show [save] button with readOnly form ', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formModel.readOnly = true; formComponent.form = formModel; const outcome = new FormOutcomeModel( formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION }); @@ -123,7 +122,7 @@ describe('FormCloudComponent', () => { }); it('should show [custom-outcome] button with readOnly form and selected custom-outcome', () => { - const formModel = new FormCloud({ selectedOutcome: 'custom-outcome' }); + const formModel = new FormModel({ selectedOutcome: 'custom-outcome' }); formModel.readOnly = true; formComponent.form = formModel; let outcome = new FormOutcomeModel( formModel, { id: '$customoutome', name: 'custom-outcome' }); @@ -137,7 +136,7 @@ describe('FormCloudComponent', () => { }); it('should allow controlling [save] button visibility', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formModel.readOnly = false; formComponent.form = formModel; const outcome = new FormOutcomeModel( formModel, { id: '$save', name: FormOutcomeModel.COMPLETE_ACTION }); @@ -164,7 +163,7 @@ describe('FormCloudComponent', () => { }); }); - spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({})); + spyOn(formCloudService, 'getTaskVariables').and.returnValue(of([])); spyOn(formCloudService, 'getTask').and.callFake((currentTaskId) => { return new Observable((observer) => { observer.next({ formRepresentation: { taskId: currentTaskId } }); @@ -189,7 +188,7 @@ describe('FormCloudComponent', () => { }); }); - spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({})); + spyOn(formCloudService, 'getTaskVariables').and.returnValue(of([])); formComponent.appName = 'test-app'; formComponent.taskId = null; @@ -239,7 +238,7 @@ describe('FormCloudComponent', () => { it('should call the process storage to retrieve the folder with only the taskId', fakeAsync(() => { spyOn(formCloudService, 'getTaskForm').and.returnValue(of(cloudFormMock)); - spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({list: { entries: []}})); + spyOn(formCloudService, 'getTaskVariables').and.returnValue(of([])); spyOn(formCloudService, 'getProcessStorageFolderTask') .and.returnValue( of({nodeId : '123', path: '/a/path/type', type: 'fakeType'})); const taskId = ''; @@ -258,7 +257,7 @@ describe('FormCloudComponent', () => { it('should call the process storage to retrieve the folder with taskId and processInstanceId', fakeAsync(() => { spyOn(formCloudService, 'getTaskForm').and.returnValue(of(cloudFormMock)); - spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({list: { entries: []}})); + spyOn(formCloudService, 'getTaskVariables').and.returnValue(of([])); spyOn(formCloudService, 'getProcessStorageFolderTask') .and.returnValue( of({nodeId : '123', path: '/a/path/type', type: 'fakeType'})); const taskId = ''; @@ -311,7 +310,7 @@ describe('FormCloudComponent', () => { }); it('should complete form on custom outcome click', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcomeName = 'Custom Action'; const outcome = new FormOutcomeModel( formModel, { id: 'custom1', name: outcomeName }); @@ -327,7 +326,7 @@ describe('FormCloudComponent', () => { }); it('should save form on [save] outcome click', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcome = new FormOutcomeModel( formModel, { id: FormCloudComponent.SAVE_OUTCOME_ID, name: 'Save', @@ -343,7 +342,7 @@ describe('FormCloudComponent', () => { }); it('should complete form on [complete] outcome click', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcome = new FormOutcomeModel( formModel, { id: FormCloudComponent.COMPLETE_OUTCOME_ID, name: 'Complete', @@ -359,7 +358,7 @@ describe('FormCloudComponent', () => { }); it('should emit form saved event on custom outcome click', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcome = new FormOutcomeModel( formModel, { id: FormCloudComponent.CUSTOM_OUTCOME_ID, name: 'Custom', @@ -376,7 +375,7 @@ describe('FormCloudComponent', () => { }); it('should do nothing when clicking outcome for readonly form', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcomeName = 'Custom Action'; const outcome = new FormOutcomeModel( formModel, { id: 'custom1', name: outcomeName }); @@ -389,13 +388,13 @@ describe('FormCloudComponent', () => { }); it('should require outcome model when clicking outcome', () => { - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); formComponent.readOnly = false; expect(formComponent.onOutcomeClicked(null)).toBeFalsy(); }); it('should require loaded form when clicking outcome', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcomeName = 'Custom Action'; const outcome = new FormOutcomeModel( formModel, { id: 'custom1', name: outcomeName }); @@ -405,7 +404,7 @@ describe('FormCloudComponent', () => { }); it('should not execute unknown system outcome', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); const outcome = new FormOutcomeModel( formModel, { id: 'unknown', name: 'Unknown', isSystem: true }); formComponent.form = formModel; @@ -413,7 +412,7 @@ describe('FormCloudComponent', () => { }); it('should require custom action name to complete form', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); let outcome = new FormOutcomeModel( formModel, { id: 'custom' }); formComponent.form = formModel; @@ -429,7 +428,7 @@ describe('FormCloudComponent', () => { const taskId = '456'; spyOn(formCloudService, 'getTask').and.returnValue(of({})); - spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({})); + spyOn(formCloudService, 'getTaskVariables').and.returnValue(of([])); spyOn(formCloudService, 'getTaskForm').and.returnValue(of({ taskId: taskId, selectedOutcome: 'custom-outcome' })); formComponent.formLoaded.subscribe(() => { @@ -448,7 +447,7 @@ describe('FormCloudComponent', () => { const error = 'Some error'; spyOn(formCloudService, 'getTask').and.returnValue(of({})); - spyOn(formCloudService, 'getTaskVariables').and.returnValue(of({})); + spyOn(formCloudService, 'getTaskVariables').and.returnValue(of([])); spyOn(formComponent, 'handleError').and.stub(); spyOn(formCloudService, 'getTaskForm').and.callFake(() => { return throwError(error); @@ -505,7 +504,7 @@ describe('FormCloudComponent', () => { const appName = 'test-app'; const processInstanceId = '333-444'; - const formModel = new FormCloud({ + const formModel = new FormModel({ id: '23', taskId: taskId, fields: [ @@ -532,7 +531,7 @@ describe('FormCloudComponent', () => { const taskId = '123-223'; const appName = 'test-app'; - const formModel = new FormCloud({ + const formModel = new FormModel({ id: '23', taskId: taskId, fields: [ @@ -555,7 +554,7 @@ describe('FormCloudComponent', () => { formComponent.form = null; formComponent.saveTaskForm(); - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); formComponent.appName = 'test-app'; formComponent.saveTaskForm(); @@ -573,7 +572,7 @@ describe('FormCloudComponent', () => { formComponent.form = null; formComponent.completeTaskForm('save'); - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); formComponent.appName = 'test-app'; formComponent.completeTaskForm('complete'); @@ -600,7 +599,7 @@ describe('FormCloudComponent', () => { const appName = 'test-app'; const processInstanceId = '333-444'; - const formModel = new FormCloud({ + const formModel = new FormModel({ id: '23', taskId: taskId, fields: [ @@ -646,12 +645,12 @@ describe('FormCloudComponent', () => { it('should prevent default outcome execution', () => { - const outcome = new FormOutcomeModel( new FormCloud(), { + const outcome = new FormOutcomeModel( new FormModel(), { id: FormCloudComponent.CUSTOM_OUTCOME_ID, name: 'Custom' }); - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); formComponent.executeOutcome.subscribe((event: FormOutcomeEvent) => { expect(event.outcome).toBe(outcome); event.preventDefault(); @@ -663,12 +662,12 @@ describe('FormCloudComponent', () => { }); it('should not prevent default outcome execution', () => { - const outcome = new FormOutcomeModel( new FormCloud(), { + const outcome = new FormOutcomeModel( new FormModel(), { id: FormCloudComponent.CUSTOM_OUTCOME_ID, name: 'Custom' }); - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); formComponent.executeOutcome.subscribe((event: FormOutcomeEvent) => { expect(event.outcome).toBe(outcome); expect(event.defaultPrevented).toBeFalsy(); @@ -691,17 +690,17 @@ describe('FormCloudComponent', () => { formComponent.checkVisibility(field); expect(visibilityService.refreshVisibility).not.toHaveBeenCalled(); - field = new FormFieldModel( new FormCloud()); + field = new FormFieldModel( new FormModel()); formComponent.checkVisibility(field); expect(visibilityService.refreshVisibility).toHaveBeenCalledWith(field.form); }); it('should disable outcome buttons for readonly form', () => { - const formModel = new FormCloud(); + const formModel = new FormModel(); formModel.readOnly = true; formComponent.form = formModel; - const outcome = new FormOutcomeModel( new FormCloud(), { + const outcome = new FormOutcomeModel( new FormModel(), { id: FormCloudComponent.CUSTOM_OUTCOME_ID, name: 'Custom' }); @@ -710,12 +709,12 @@ describe('FormCloudComponent', () => { }); it('should require outcome to eval button state', () => { - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); expect(formComponent.isOutcomeButtonEnabled(null)).toBeFalsy(); }); it('should disable complete outcome button when disableCompleteButton is true', () => { - const formModel = new FormCloud(cloudFormMock); + const formModel = new FormModel(cloudFormMock); formComponent.form = formModel; formComponent.disableCompleteButton = true; @@ -730,7 +729,7 @@ describe('FormCloudComponent', () => { }); it('should disable save outcome button when disableSaveButton is true', () => { - const formModel = new FormCloud(cloudFormMock); + const formModel = new FormModel(cloudFormMock); formComponent.form = formModel; formComponent.disableSaveButton = true; @@ -745,7 +744,7 @@ describe('FormCloudComponent', () => { }); it('should disable start process outcome button when disableStartProcessButton is true', () => { - const formModel = new FormCloud(cloudFormMock); + const formModel = new FormModel(cloudFormMock); formComponent.form = formModel; formComponent.disableStartProcessButton = true; @@ -764,17 +763,17 @@ describe('FormCloudComponent', () => { done(); }); - const outcome = new FormOutcomeModel( new FormCloud(), { + const outcome = new FormOutcomeModel( new FormModel(), { id: FormCloudComponent.CUSTOM_OUTCOME_ID, name: 'Custom' }); - formComponent.form = new FormCloud(); + formComponent.form = new FormModel(); formComponent.onOutcomeClicked(outcome); }); it('should refresh form values when data is changed', (done) => { - formComponent.form = new FormCloud(JSON.parse(JSON.stringify(cloudFormMock))); + formComponent.form = new FormModel(JSON.parse(JSON.stringify(cloudFormMock))); formComponent.formCloudRepresentationJSON = new FormCloudRepresentation(JSON.parse(JSON.stringify(cloudFormMock))); let formFields = formComponent.form.getFormFields(); @@ -803,7 +802,7 @@ describe('FormCloudComponent', () => { }); it('should refresh radio buttons value when id is given to data', () => { - formComponent.form = new FormCloud(JSON.parse(JSON.stringify(cloudFormMock))); + formComponent.form = new FormModel(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'); diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts index 028aebd58c..8625bb0544 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts @@ -32,14 +32,16 @@ import { NotificationService, FormRenderingService, FORM_FIELD_VALIDATORS, - FormFieldValidator + FormFieldValidator, + FormValues, + FormModel } from '@alfresco/adf-core'; import { FormCloudService } from '../services/form-cloud.service'; -import { FormCloud } from '../models/form-cloud.model'; import { TaskVariableCloud } from '../models/task-variable-cloud.model'; import { DropdownCloudWidgetComponent } from './dropdown-cloud/dropdown-cloud.widget'; import { AttachFileCloudWidgetComponent } from './attach-file-cloud-widget/attach-file-cloud-widget.component'; import { DateCloudWidgetComponent } from './date-cloud/date-cloud.widget'; +import { TaskDetailsCloudModel } from '../../task/start-task/models/task-details-cloud.model'; @Component({ selector: 'adf-cloud-form', @@ -61,7 +63,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, /** Underlying form model instance. */ @Input() - form: FormCloud; + form: FormModel; /** Task id to fetch corresponding form and values. */ @Input() @@ -76,22 +78,22 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, /** Emitted when the form is submitted with the `Save` or custom outcomes. */ @Output() - formSaved: EventEmitter = new EventEmitter(); + formSaved = new EventEmitter(); /** Emitted when the form is submitted with the `Complete` outcome. */ @Output() - formCompleted: EventEmitter = new EventEmitter(); + formCompleted = new EventEmitter(); /** Emitted when the form is loaded or reloaded. */ @Output() - formLoaded: EventEmitter = new EventEmitter(); + formLoaded = new EventEmitter(); /** Emitted when form values are refreshed due to a data property change. */ @Output() - formDataRefreshed: EventEmitter = new EventEmitter(); + formDataRefreshed = new EventEmitter(); @Output() - formContentClicked: EventEmitter = new EventEmitter(); + formContentClicked = new EventEmitter(); protected subscriptions: Subscription[] = []; nodeId: string; @@ -162,24 +164,24 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, } - findProcessVariablesByTaskId(appName: string, taskId: string): Observable { + findProcessVariablesByTaskId(appName: string, taskId: string): Observable { return this.formCloudService.getTask(appName, taskId).pipe( - switchMap((task: any) => { + switchMap(task => { if (this.isAProcessTask(task)) { return this.formCloudService.getTaskVariables(appName, taskId); } else { - return of({}); + return of([]); } }) ); } - isAProcessTask(taskRepresentation) { + isAProcessTask(taskRepresentation: TaskDetailsCloudModel): boolean { return taskRepresentation.processDefinitionId && taskRepresentation.processDefinitionDeploymentId !== 'null'; } - getFormByTaskId(appName: string, taskId: string): Promise { - return new Promise(resolve => { + getFormByTaskId(appName: string, taskId: string): Promise { + return new Promise(resolve => { forkJoin(this.formCloudService.getTaskForm(appName, taskId), this.formCloudService.getTaskVariables(appName, taskId)) .pipe(takeUntil(this.onDestroy$)) @@ -255,7 +257,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, saveTaskForm() { if (this.form && this.appName && this.taskId) { this.formCloudService - .saveTaskForm(this.appName, this.taskId, this.processInstanceId, this.form.id, this.form.values) + .saveTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values) .pipe(takeUntil(this.onDestroy$)) .subscribe( () => { @@ -269,7 +271,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, completeTaskForm(outcome?: string) { if (this.form && this.appName && this.taskId) { this.formCloudService - .completeTaskForm(this.appName, this.taskId, this.processInstanceId, this.form.id, this.form.values, outcome) + .completeTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values, outcome) .pipe(takeUntil(this.onDestroy$)) .subscribe( () => { @@ -280,9 +282,14 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, } } - parseForm(formCloudRepresentationJSON: any): FormCloud { + parseForm(formCloudRepresentationJSON: any): FormModel { if (formCloudRepresentationJSON) { - const form = new FormCloud(formCloudRepresentationJSON, this.data, this.readOnly, this.formCloudService); + const formValues: FormValues = {}; + (this.data || []).forEach(variable => { + formValues[variable.name] = variable.value; + }); + + const form = new FormModel(formCloudRepresentationJSON, formValues, this.readOnly); if (!form || !form.fields.length) { form.outcomes = this.getFormDefinitionOutcomes(form); } @@ -298,7 +305,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, * Get custom set of outcomes for a Form Definition. * @param form Form definition model. */ - getFormDefinitionOutcomes(form: FormCloud): FormOutcomeModel[] { + getFormDefinitionOutcomes(form: FormModel): FormOutcomeModel[] { return [ new FormOutcomeModel( form, { id: '$save', name: FormOutcomeModel.SAVE_ACTION, isSystem: true }) ]; @@ -316,15 +323,15 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, this.onFormDataRefreshed(this.form); } - protected onFormLoaded(form: FormCloud) { + protected onFormLoaded(form: FormModel) { this.formLoaded.emit(form); } - protected onFormDataRefreshed(form: FormCloud) { + protected onFormDataRefreshed(form: FormModel) { this.formDataRefreshed.emit(form); } - protected onTaskSaved(form: FormCloud) { + protected onTaskSaved(form: FormModel) { this.formSaved.emit(form); } @@ -332,7 +339,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, this.handleError(error); } - protected onTaskCompleted(form: FormCloud) { + protected onTaskCompleted(form: FormModel) { this.formCompleted.emit(form); } diff --git a/lib/process-services-cloud/src/lib/form/models/form-cloud.model.spec.ts b/lib/process-services-cloud/src/lib/form/models/form-cloud.model.spec.ts index c2836b686e..bc6e3cc358 100644 --- a/lib/process-services-cloud/src/lib/form/models/form-cloud.model.spec.ts +++ b/lib/process-services-cloud/src/lib/form/models/form-cloud.model.spec.ts @@ -15,22 +15,14 @@ * limitations under the License. */ -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 { TabModel, FormFieldModel, ContainerModel, FormOutcomeModel, FormFieldTypes, FormModel } from '@alfresco/adf-core'; import { FormCloudRepresentation } from './form-cloud-representation.model'; describe('FormCloud', () => { - let formCloudService: FormCloudService; - - beforeEach(() => { - formCloudService = new FormCloudService(null, new AppConfigService(null), null); - }); - it('should store original json', () => { const formRepresentation = {fields: []}; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.json).toEqual(formRepresentation); }); @@ -41,7 +33,7 @@ describe('FormCloud', () => { taskId: '', taskName: '' }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); Object.keys(formRepresentation).forEach((key) => { expect(form[key]).toEqual(form[key]); @@ -54,17 +46,17 @@ describe('FormCloud', () => { name: '', formDefinition: {} }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.taskName).toBe(formRepresentation.name); }); it('should set readonly state from params', () => { - const form = new FormCloud({}, null, true); + const form = new FormModel({}, null, true); expect(form.readOnly).toBeTruthy(); }); it('should check tabs', () => { - const form = new FormCloud(); + const form = new FormModel(); form.tabs = null; expect(form.hasTabs()).toBeFalsy(); @@ -77,7 +69,7 @@ describe('FormCloud', () => { }); it('should check fields', () => { - const form = new FormCloud(); + const form = new FormModel(); form.fields = null; expect(form.hasFields()).toBeFalsy(); @@ -91,7 +83,7 @@ describe('FormCloud', () => { }); it('should check outcomes', () => { - const form = new FormCloud(); + const form = new FormModel(); form.outcomes = null; expect(form.hasOutcomes()).toBeFalsy(); @@ -111,7 +103,7 @@ describe('FormCloud', () => { ] }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.tabs.length).toBe(2); expect(form.tabs[0].id).toBe('tab1'); expect(form.tabs[1].id).toBe('tab2'); @@ -131,7 +123,7 @@ describe('FormCloud', () => { ] }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.fields.length).toBe(2); expect(form.fields[0].id).toBe('field1'); expect(form.fields[1].id).toBe('field2'); @@ -142,7 +134,7 @@ describe('FormCloud', () => { fields: null }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.fields).toBeDefined(); expect(form.fields.length).toBe(0); }); @@ -161,7 +153,7 @@ describe('FormCloud', () => { ] }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.tabs.length).toBe(2); expect(form.fields.length).toBe(4); @@ -182,16 +174,16 @@ describe('FormCloud', () => { ] }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.outcomes.length).toBe(3); - expect(form.outcomes[0].id).toBe(FormCloud.SAVE_OUTCOME); + expect(form.outcomes[0].id).toBe(FormModel.SAVE_OUTCOME); expect(form.outcomes[0].isSystem).toBeTruthy(); - expect(form.outcomes[1].id).toBe(FormCloud.COMPLETE_OUTCOME); + expect(form.outcomes[1].id).toBe(FormModel.COMPLETE_OUTCOME); expect(form.outcomes[1].isSystem).toBeTruthy(); - expect(form.outcomes[2].id).toBe(FormCloud.START_PROCESS_OUTCOME); + expect(form.outcomes[2].id).toBe(FormModel.START_PROCESS_OUTCOME); expect(form.outcomes[2].isSystem).toBeTruthy(); }); @@ -199,7 +191,7 @@ describe('FormCloud', () => { const formRepresentation = { fields: null }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.outcomes.length).toBe(0); }); @@ -213,10 +205,10 @@ describe('FormCloud', () => { ] }; - const form = new FormCloud(formRepresentation); + const form = new FormModel(formRepresentation); expect(form.outcomes.length).toBe(2); - expect(form.outcomes[0].id).toBe(FormCloud.SAVE_OUTCOME); + expect(form.outcomes[0].id).toBe(FormModel.SAVE_OUTCOME); expect(form.outcomes[0].isSystem).toBeTruthy(); expect(form.outcomes[1].id).toBe('custom-1'); @@ -224,7 +216,7 @@ describe('FormCloud', () => { }); it('should get field by id', () => { - const form = new FormCloud({}, null, false, formCloudService); + const form = new FormModel({}, null, false); const field: any = { id: 'field1' }; spyOn(form, 'getFormFields').and.returnValue([field]); diff --git a/lib/process-services-cloud/src/lib/form/models/form-cloud.model.ts b/lib/process-services-cloud/src/lib/form/models/form-cloud.model.ts deleted file mode 100644 index bc136370cd..0000000000 --- a/lib/process-services-cloud/src/lib/form/models/form-cloud.model.ts +++ /dev/null @@ -1,212 +0,0 @@ -/*! - * @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. - */ - -import { - TabModel, FormWidgetModel, FormOutcomeModel, FormValues, - FormWidgetModelCache, FormFieldModel, ContainerModel, FormFieldTypes, - ValidateFormFieldEvent, FormFieldValidator, FormFieldTemplates, FormBaseModel, FORM_FIELD_VALIDATORS } from '@alfresco/adf-core'; -import { FormCloudService } from '../services/form-cloud.service'; -import { TaskVariableCloud } from './task-variable-cloud.model'; - -export class FormCloud extends FormBaseModel { - - static SAVE_OUTCOME: string = '$save'; - static COMPLETE_OUTCOME: string = '$complete'; - static START_PROCESS_OUTCOME: string = '$startProcess'; - - readonly id: string; - nodeId: string; - contentHost: string; - readonly name: string; - readonly taskId: string; - readonly taskName: string; - - readonly selectedOutcome: string; - - readOnly: boolean; - processDefinitionId: any; - className: string; - values: FormValues = {}; - - tabs: TabModel[] = []; - fields: FormWidgetModel[] = []; - outcomes: FormOutcomeModel[] = []; - customFieldTemplates: FormFieldTemplates = {}; - fieldValidators: FormFieldValidator[] = [...FORM_FIELD_VALIDATORS]; - - constructor(formCloudRepresentationJSON?: any, formData?: TaskVariableCloud[], readOnly: boolean = false, protected formService?: FormCloudService) { - super(); - this.readOnly = readOnly; - - 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 = {}; - - this.tabs = (formCloudRepresentationJSON.tabs || []).map((t) => { - const model = new TabModel( this, t); - tabCache[model.id] = model; - return model; - }); - - this.fields = this.parseRootFields(formCloudRepresentationJSON); - - if (formData && formData.length > 0) { - this.loadData(formData); - } - - for (let i = 0; i < this.fields.length; i++) { - const field = this.fields[i]; - if (field.tab) { - const tab = tabCache[field.tab]; - if (tab) { - tab.fields.push(field); - } - } - } - - if (formCloudRepresentationJSON.fields) { - const saveOutcome = new FormOutcomeModel( this, { - id: FormCloud.SAVE_OUTCOME, - name: 'SAVE', - isSystem: true - }); - const completeOutcome = new FormOutcomeModel( this, { - id: FormCloud.COMPLETE_OUTCOME, - name: 'COMPLETE', - isSystem: true - }); - const startProcessOutcome = new FormOutcomeModel( this, { - id: FormCloud.START_PROCESS_OUTCOME, - name: 'START PROCESS', - isSystem: true - }); - - const customOutcomes = (formCloudRepresentationJSON.outcomes || []).map((obj) => new FormOutcomeModel( this, obj)); - - this.outcomes = [saveOutcome].concat( - customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome] - ); - } - } - - this.validateForm(); - } - - hasTabs(): boolean { - return this.tabs && this.tabs.length > 0; - } - - hasFields(): boolean { - return this.fields && this.fields.length > 0; - } - - hasOutcomes(): boolean { - return this.outcomes && this.outcomes.length > 0; - } - - onFormFieldChanged(field: FormFieldModel) { - this.validateField(field); - } - - validateForm() { - const errorsField: FormFieldModel[] = []; - - const fields = this.getFormFields(); - for (let i = 0; i < fields.length; i++) { - if (!fields[i].validate()) { - errorsField.push(fields[i]); - } - } - - this.isValid = errorsField.length > 0 ? false : true; - } - - /** - * Validates a specific form field, triggers form validation. - * - * @param field Form field to validate. - * @memberof FormCloud - */ - validateField(field: FormFieldModel) { - if (!field) { - return; - } - - const validateFieldEvent = new ValidateFormFieldEvent( this, field); - - if (!validateFieldEvent.isValid) { - this.isValid = false; - return; - } - - if (validateFieldEvent.defaultPrevented) { - return; - } - - if (!field.validate()) { - this.isValid = false; - } - - this.validateForm(); - } - - // Activiti supports 3 types of root fields: container|group|dynamic-table - private parseRootFields(json: any): FormWidgetModel[] { - let fields = []; - - if (json.fields) { - fields = json.fields; - } - - const formWidgetModel: FormWidgetModel[] = []; - - for (const field of fields) { - if (field.type === FormFieldTypes.DISPLAY_VALUE) { - // workaround for dynamic table on a completed/readonly form - if (field.params) { - const originalField = field.params['field']; - if (originalField.type === FormFieldTypes.DYNAMIC_TABLE) { - formWidgetModel.push(new ContainerModel(new FormFieldModel( this, field))); - } - } - } else { - formWidgetModel.push(new ContainerModel(new FormFieldModel( this, field))); - } - } - - return formWidgetModel; - } - - // Loads external data and overrides field values - // Typically used when form definition and form data coming from different sources - private loadData(formData: TaskVariableCloud[]) { - for (const field of this.getFormFields()) { - const fieldValue = formData.find((value) => { return value.name === field.id; }); - if (fieldValue) { - field.json.value = fieldValue.value; - field.value = field.parseValue(field.json); - } - } - } -} diff --git a/lib/process-services-cloud/src/lib/form/models/form-definition-selector-cloud.model.ts b/lib/process-services-cloud/src/lib/form/models/form-definition-selector-cloud.model.ts index f24b543afc..845be58160 100644 --- a/lib/process-services-cloud/src/lib/form/models/form-definition-selector-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/form/models/form-definition-selector-cloud.model.ts @@ -15,21 +15,10 @@ * limitations under the License. */ -export class FormDefinitionSelectorCloudModel { - - id: number; - name: string; - description: string; - version: string; - standAlone: string; - - constructor(obj?: any) { - if (obj) { - this.id = obj.id || null; - this.name = obj.name || null; - this.description = obj.description || null; - this.version = obj.version || null; - this.standAlone = obj.standAlone || null; - } - } +export interface FormDefinitionSelectorCloudModel { + id?: number; + name?: string; + description?: string; + version?: string; + standAlone?: string; } diff --git a/lib/process-services-cloud/src/lib/form/public-api.ts b/lib/process-services-cloud/src/lib/form/public-api.ts index e31067eda3..b6f70a62ef 100644 --- a/lib/process-services-cloud/src/lib/form/public-api.ts +++ b/lib/process-services-cloud/src/lib/form/public-api.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -export * from './models/form-cloud.model'; export * from './models/task-variable-cloud.model'; export * from './models/form-definition-selector-cloud.model'; diff --git a/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts b/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts index 295622263b..721a5799eb 100644 --- a/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts @@ -16,12 +16,11 @@ */ import { Injectable } from '@angular/core'; -import { AlfrescoApiService, LogService, FormValues, AppConfigService, FormOutcomeModel, FormFieldOption } from '@alfresco/adf-core'; +import { AlfrescoApiService, LogService, FormValues, AppConfigService, FormOutcomeModel, FormFieldOption, FormModel } from '@alfresco/adf-core'; import { throwError, Observable, from } from 'rxjs'; import { catchError, map, switchMap } from 'rxjs/operators'; import { TaskDetailsCloudModel } from '../../task/start-task/models/task-details-cloud.model'; import { SaveFormRepresentation, CompleteFormRepresentation } from '@alfresco/js-api'; -import { FormCloud } from '../models/form-cloud.model'; import { TaskVariableCloud, ProcessStorageCloudModel } from '../models/task-variable-cloud.model'; import { BaseCloudService } from '../../services/base-cloud.service'; @@ -258,12 +257,17 @@ export class FormCloudService extends BaseCloudService { * @param readOnly Toggles whether or not the form should be read-only * @returns Form created from the JSON specification */ - parseForm(json: any, data?: TaskVariableCloud[], readOnly: boolean = false): FormCloud { + parseForm(json: any, data?: TaskVariableCloud[], readOnly: boolean = false): FormModel { if (json) { const flattenForm = {...json.formRepresentation, ...json.formRepresentation.formDefinition}; delete flattenForm.formDefinition; - const form = new FormCloud(flattenForm, data, readOnly, this); + const formValues: FormValues = {}; + (data || []).forEach(variable => { + formValues[variable.name] = variable.value; + }); + + const form = new FormModel(flattenForm, formValues, readOnly); if (!json.fields) { form.outcomes = [ new FormOutcomeModel( form, { diff --git a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts index b2f687c9cb..2f8c43e901 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts @@ -23,13 +23,13 @@ import { import { ProcessInstanceCloud } from '../models/process-instance-cloud.model'; import { StartProcessCloudService } from '../services/start-process-cloud.service'; import { FormControl, Validators, FormGroup, AbstractControl, FormBuilder, ValidatorFn } from '@angular/forms'; +import { FormModel } from '@alfresco/adf-core'; import { MatAutocompleteTrigger } from '@angular/material'; import { ProcessPayloadCloud } from '../models/process-payload-cloud.model'; import { debounceTime, takeUntil } from 'rxjs/operators'; import { ProcessDefinitionCloud } from '../models/process-definition-cloud.model'; import { Subject } from 'rxjs'; import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model'; -import { FormCloud } from '../../../form/models/form-cloud.model'; @Component({ selector: 'adf-cloud-start-process', @@ -74,15 +74,15 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy /** Emitted when the process is successfully started. */ @Output() - success: EventEmitter = new EventEmitter(); + success = new EventEmitter(); /** Emitted when the starting process is cancelled */ @Output() - cancel: EventEmitter = new EventEmitter(); + cancel = new EventEmitter(); /** Emitted when an error occurs. */ @Output() - error: EventEmitter = new EventEmitter(); + error = new EventEmitter(); processDefinitionList: ProcessDefinitionCloud[] = []; processDefinitionCurrent: ProcessDefinitionCloud; @@ -92,8 +92,9 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy filteredProcesses: ProcessDefinitionCloud[] = []; isLoading = false; isFormCloudLoaded = false; - formCloud: FormCloud; + formCloud: FormModel; protected onDestroy$ = new Subject(); + constructor(private startProcessCloudService: StartProcessCloudService, private formBuilder: FormBuilder) { } @@ -128,7 +129,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy return this.processDefinitionCurrent && !!this.processDefinitionCurrent.formKey; } - onFormLoaded(form: FormCloud) { + onFormLoaded(form: FormModel) { this.isFormCloudLoaded = true; this.formCloud = form; } diff --git a/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts b/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts index da403bc255..df99d614e5 100644 --- a/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/task/start-task/models/task-details-cloud.model.ts @@ -44,6 +44,7 @@ export class TaskDetailsCloudModel { managerOfCandidateGroup: boolean; memberOfCandidateGroup: boolean; memberOfCandidateUsers: boolean; + processDefinitionDeploymentId?: string; constructor(obj?: any) { if (obj) { diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts index dcc0e972de..375abe3e5d 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts @@ -19,10 +19,9 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; -import { FormCloud } from '../../../form/models/form-cloud.model'; import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model'; import { TaskCloudService } from '../../services/task-cloud.service'; -import { FormRenderingService, ContentLinkModel } from '@alfresco/adf-core'; +import { FormRenderingService, FormModel, ContentLinkModel } from '@alfresco/adf-core'; import { AttachFileCloudWidgetComponent } from '../../../form/components/attach-file-cloud-widget/attach-file-cloud-widget.component'; import { DropdownCloudWidgetComponent } from '../../../form/components/dropdown-cloud/dropdown-cloud.widget'; import { DateCloudWidgetComponent } from '../../../form/components/date-cloud/date-cloud.widget'; @@ -64,31 +63,31 @@ export class TaskFormCloudComponent implements OnChanges { /** Emitted when the form is saved. */ @Output() - formSaved: EventEmitter = new EventEmitter(); + formSaved = new EventEmitter(); /** Emitted when the form is submitted with the `Complete` outcome. */ @Output() - formCompleted: EventEmitter = new EventEmitter(); + formCompleted = new EventEmitter(); /** Emitted when the task is completed. */ @Output() - taskCompleted: EventEmitter = new EventEmitter(); + taskCompleted = new EventEmitter(); /** Emitted when the task is claimed. */ @Output() - taskClaimed: EventEmitter = new EventEmitter(); + taskClaimed = new EventEmitter(); /** Emitted when the task is unclaimed. */ @Output() - taskUnclaimed: EventEmitter = new EventEmitter(); + taskUnclaimed = new EventEmitter(); /** Emitted when the cancel button is clicked. */ @Output() - cancelClick: EventEmitter = new EventEmitter(); + cancelClick = new EventEmitter(); /** Emitted when any error occurs. */ @Output() - error: EventEmitter = new EventEmitter(); + error = new EventEmitter(); @Output() formContentClicked: EventEmitter = new EventEmitter(); @@ -171,11 +170,11 @@ export class TaskFormCloudComponent implements OnChanges { this.cancelClick.emit(this.taskId); } - onFormSaved(form: FormCloud) { + onFormSaved(form: FormModel) { this.formSaved.emit(form); } - onFormCompleted(form: FormCloud) { + onFormCompleted(form: FormModel) { this.formCompleted.emit(form); this.taskCompleted.emit(this.taskId); }