diff --git a/ng2-components/ng2-activiti-form/index.ts b/ng2-components/ng2-activiti-form/index.ts index 4fe5c5d489..519cc0e2c3 100644 --- a/ng2-components/ng2-activiti-form/index.ts +++ b/ng2-components/ng2-activiti-form/index.ts @@ -19,6 +19,7 @@ import { NgModule, ModuleWithProviders } from '@angular/core'; import { CoreModule } from 'ng2-alfresco-core'; import { ActivitiForm } from './src/components/activiti-form.component'; +import { ActivitiStartForm } from './src/components/activiti-start-form.component'; import { FormService } from './src/services/form.service'; import { EcmModelService } from './src/services/ecm-model.service'; import { NodeService } from './src/services/node.service'; @@ -28,6 +29,7 @@ import { HttpModule } from '@angular/http'; import { WIDGET_DIRECTIVES } from './src/components/widgets/index'; export * from './src/components/activiti-form.component'; +export * from './src/components/activiti-start-form.component'; export * from './src/services/form.service'; export * from './src/components/widgets/index'; export * from './src/services/ecm-model.service'; @@ -35,6 +37,7 @@ export * from './src/services/node.service'; export const ACTIVITI_FORM_DIRECTIVES: any[] = [ ActivitiForm, + ActivitiStartForm, ...WIDGET_DIRECTIVES ]; diff --git a/ng2-components/ng2-activiti-form/src/assets/translation.service.mock.ts b/ng2-components/ng2-activiti-form/src/assets/translation.service.mock.ts new file mode 100644 index 0000000000..e0aa69addb --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/assets/translation.service.mock.ts @@ -0,0 +1,28 @@ +/*! + * @license + * Copyright 2016 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 { Observable } from 'rxjs/Rx'; + +export class TranslationMock { + + get(key: string|Array, interpolateParams?: Object): Observable { + return Observable.of(key); + } + + addTranslationFolder() { + } +} diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts index 7abd992b9f..e25ee1e82c 100644 --- a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts +++ b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts @@ -145,7 +145,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { debugMode: boolean = false; - constructor(private formService: FormService, + constructor(protected formService: FormService, private visibilityService: WidgetVisibilityService, private ecmModelService: EcmModelService, private nodeService: NodeService) { diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.html b/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.html new file mode 100644 index 0000000000..e1ee54a494 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.html @@ -0,0 +1,35 @@ +
+
+
+
+ {{ form.isValid ? 'event_available' : 'event_busy' }} +

{{form.taskName}}

+
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+
+
+
diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.spec.ts b/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.spec.ts new file mode 100644 index 0000000000..46d20208d6 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.spec.ts @@ -0,0 +1,134 @@ +/*! + * @license + * Copyright 2016 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 { SimpleChange } from '@angular/core'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { Observable } from 'rxjs/Rx'; + +import { ActivitiStartForm } from './activiti-start-form.component'; +import { WIDGET_DIRECTIVES } from './widgets/index'; +import { FormService } from './../services/form.service'; +import { EcmModelService } from './../services/ecm-model.service'; +import { WidgetVisibilityService } from './../services/widget-visibility.service'; +import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; +import { TranslationMock } from './../assets/translation.service.mock'; + +describe('ActivitiStartForm', () => { + + let componentHandler: any; + let formService: FormService; + let component: ActivitiStartForm; + let fixture: ComponentFixture; + let getStartFormSpy: jasmine.Spy; + + const exampleId1 = 'my:process1'; + const exampleId2 = 'my:process2'; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule ], + declarations: [ + ActivitiStartForm, + ...WIDGET_DIRECTIVES + ], + providers: [ + { provide: AlfrescoTranslationService, useClass: TranslationMock }, + EcmModelService, + FormService, + WidgetVisibilityService + ] + }).compileComponents(); + })); + + beforeEach(() => { + + fixture = TestBed.createComponent(ActivitiStartForm); + component = fixture.componentInstance; + formService = fixture.debugElement.injector.get(FormService); + + getStartFormSpy = spyOn(formService, 'getStartFormDefinition').and.returnValue(Observable.of({ + processDefinitionName: 'my:process' + })); + + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered', + 'upgradeElement' + ]); + window['componentHandler'] = componentHandler; + }); + + it('should load start form on init if processDefinitionId defined', () => { + component.processDefinitionId = exampleId1; + component.ngOnInit(); + expect(formService.getStartFormDefinition).toHaveBeenCalled(); + }); + + it('should load not start form on init if no processDefinitionId defined', () => { + component.ngOnInit(); + expect(formService.getStartFormDefinition).not.toHaveBeenCalled(); + }); + + it('should load start form when processDefinitionId changed', () => { + component.processDefinitionId = exampleId1; + component.ngOnChanges({processDefinitionId: new SimpleChange(exampleId1, exampleId2)}); + expect(formService.getStartFormDefinition).toHaveBeenCalled(); + }); + + it('should not load start form when changes notified but no change to processDefinitionId', () => { + component.processDefinitionId = exampleId1; + component.ngOnChanges({otherProp: new SimpleChange(exampleId1, exampleId2)}); + expect(formService.getStartFormDefinition).not.toHaveBeenCalled(); + }); + + it('should consume errors encountered when loading start form', () => { + getStartFormSpy.and.returnValue(Observable.throw({})); + component.processDefinitionId = exampleId1; + component.ngOnInit(); + }); + + it('should not show outcome buttons by default', () => { + getStartFormSpy.and.returnValue(Observable.of({ + id: '1', + processDefinitionName: 'my:process', + outcomes: [{ + id: 'approve', + name: 'Approve' + }] + })); + component.processDefinitionId = exampleId1; + component.ngOnInit(); + fixture.detectChanges(); + expect(component.outcomesContainer).not.toBeTruthy(); + }); + + it('should show outcome buttons if showOutcomeButtons is true', () => { + getStartFormSpy.and.returnValue(Observable.of({ + id: '1', + processDefinitionName: 'my:process', + outcomes: [{ + id: 'approve', + name: 'Approve' + }] + })); + component.processDefinitionId = exampleId1; + component.showOutcomeButtons = true; + component.ngOnInit(); + fixture.detectChanges(); + expect(component.outcomesContainer).toBeTruthy(); + }); + +}); diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.ts b/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.ts new file mode 100644 index 0000000000..4a165f2c06 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/activiti-start-form.component.ts @@ -0,0 +1,115 @@ +/*! + * @license + * Copyright 2016 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 { + Component, + OnInit, AfterViewChecked, OnChanges, + SimpleChanges, + Input, + ViewChild, + ElementRef +} from '@angular/core'; +import { AlfrescoTranslationService } from 'ng2-alfresco-core'; +import { ActivitiForm } from './activiti-form.component'; +import { FormService } from './../services/form.service'; +import { WidgetVisibilityService } from './../services/widget-visibility.service'; + +/** + * Displays the start form for a named process definition, which can be used to retrieve values to start a new process. + * + * After the form has been completed the form values are available from the attribute component.form.values and + * component.form.isValid (boolean) can be used to check the if the form is valid or not. Both of these properties are + * updated as the user types into the form. + * + * @Input + * {processDefinitionId} string: The process definition ID + * {showOutcomeButtons} boolean: Whether form outcome buttons should be shown, as yet these don't do anything so this + * is false by default + * @Output + * {formLoaded} EventEmitter - This event is fired when the form is loaded, it pass all the value in the form. + * {formSaved} EventEmitter - This event is fired when the form is saved, it pass all the value in the form. + * {formCompleted} EventEmitter - This event is fired when the form is completed, it pass all the value in the form. + * + * @returns {ActivitiForm} . + */ +@Component({ + moduleId: module.id, + selector: 'activiti-start-form', + templateUrl: './activiti-start-form.component.html', + styleUrls: ['./activiti-form.component.css'] +}) +export class ActivitiStartForm extends ActivitiForm implements OnInit, AfterViewChecked, OnChanges { + + @Input() + processDefinitionId: string; + + @Input() + showOutcomeButtons: boolean = false; + + @ViewChild('outcomesContainer', {}) + outcomesContainer: ElementRef = null; + + constructor(private translate: AlfrescoTranslationService, + formService: FormService, + visibilityService: WidgetVisibilityService) { + super(formService, visibilityService, null, null); + } + + ngOnInit() { + this.loadForm(); + + if (this.translate) { + this.translate.addTranslationFolder('node_modules/ng2-activiti-form/src'); + } + } + + ngOnChanges(changes: SimpleChanges) { + let processId = changes['processDefinitionId']; + if (processId && processId.currentValue) { + this.getStartFormDefinition(processId.currentValue); + return; + } + } + + loadForm() { + if (this.processDefinitionId) { + this.getStartFormDefinition(this.processDefinitionId); + return; + } + } + + getStartFormDefinition(processId: string) { + this.formService + .getStartFormDefinition(processId) + .subscribe( + form => { + this.formName = form.processDefinitionName; + this.form = this.parseForm(form); + this.formLoaded.emit(this.form); + }, + (error) => { + this.handleError(error); + } + ); + } + + saveTaskForm() { + } + + completeTaskForm(outcome?: string) { + } +} diff --git a/ng2-components/ng2-activiti-form/src/i18n/en.json b/ng2-components/ng2-activiti-form/src/i18n/en.json new file mode 100644 index 0000000000..701b687e00 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/i18n/en.json @@ -0,0 +1,7 @@ +{ + "FORM": { + "START_FORM": { + "TITLE": "Start Form" + } + } +} diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts b/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts index 0243eb0f9b..c8ca4ca711 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts @@ -30,7 +30,7 @@ declare let jasmine: any; describe('FormService', () => { - let responseBody: any, service: FormService; + let responseBody: any, service: FormService, apiService: AlfrescoApiService; beforeAll(() => { TestBed.configureTestingModule({ @@ -44,6 +44,7 @@ describe('FormService', () => { ] }); service = TestBed.get(FormService); + apiService = TestBed.get(AlfrescoApiService); }); beforeEach(() => { @@ -229,6 +230,22 @@ describe('FormService', () => { }); }); + it('should get start form definition by process definition id', (done) => { + + let processApiSpy = jasmine.createSpyObj(['getProcessDefinitionStartForm']); + spyOn(apiService, 'getInstance').and.returnValue({ + activiti: { + processApi: processApiSpy + } + }); + processApiSpy.getProcessDefinitionStartForm.and.returnValue(Promise.resolve({ id: '1' })); + + service.getStartFormDefinition('myprocess:1').subscribe(result => { + expect(processApiSpy.getProcessDefinitionStartForm).toHaveBeenCalledWith('myprocess:1'); + done(); + }); + }); + it('should not get form id from response', () => { let response = new Response(new ResponseOptions({body: null})); expect(service.getFormId(response)).toBeNull(); diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.ts b/ng2-components/ng2-activiti-form/src/services/form.service.ts index 20311caacd..d367b100cd 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.ts @@ -206,6 +206,18 @@ export class FormService { .catch(this.handleError); } + /** + * Get start form definition for a given process + * @param processId Process definition ID + * @returns {Observable} + */ + getStartFormDefinition(processId: string): Observable { + return Observable.fromPromise( + this.apiService.getInstance().activiti.processApi.getProcessDefinitionStartForm(processId)) + .map(this.toJson) + .catch(this.handleError); + } + getRestFieldValues(taskId: string, field: string): Observable { let alfrescoApi = this.apiService.getInstance(); return Observable.fromPromise(alfrescoApi.activiti.taskApi.getRestFieldValues(taskId, field)); diff --git a/ng2-components/ng2-activiti-processlist/index.ts b/ng2-components/ng2-activiti-processlist/index.ts index 17db84cc7e..97e19efdaa 100644 --- a/ng2-components/ng2-activiti-processlist/index.ts +++ b/ng2-components/ng2-activiti-processlist/index.ts @@ -18,6 +18,7 @@ import { NgModule, ModuleWithProviders } from '@angular/core'; import { CoreModule } from 'ng2-alfresco-core'; import { DataTableModule } from 'ng2-alfresco-datatable'; +import { ActivitiFormModule } from 'ng2-activiti-form'; import { ActivitiTaskListModule } from 'ng2-activiti-tasklist'; import { ActivitiProcessInstanceListComponent } from './src/components/activiti-processlist.component'; @@ -54,6 +55,7 @@ export const ACTIVITI_PROCESSLIST_PROVIDERS: [any] = [ imports: [ CoreModule, DataTableModule, + ActivitiFormModule, ActivitiTaskListModule ], declarations: [ diff --git a/ng2-components/ng2-activiti-processlist/karma-test-shim.js b/ng2-components/ng2-activiti-processlist/karma-test-shim.js index fa7b29a843..b931cf3867 100644 --- a/ng2-components/ng2-activiti-processlist/karma-test-shim.js +++ b/ng2-components/ng2-activiti-processlist/karma-test-shim.js @@ -54,6 +54,7 @@ var map = { 'ng2-translate': 'npm:ng2-translate', 'alfresco-js-api': 'npm:alfresco-js-api/dist', + 'ng2-activiti-form': 'npm:ng2-activiti-form/dist', 'ng2-activiti-tasklist': 'npm:ng2-activiti-tasklist/dist', 'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist', 'ng2-alfresco-datatable': 'npm:ng2-alfresco-datatable/dist' @@ -65,6 +66,7 @@ var packages = { 'ng2-translate': { defaultExtension: 'js' }, 'alfresco-js-api': { main: './alfresco-js-api.js', defaultExtension: 'js'}, + 'ng2-activiti-form': { main: './index.js', defaultExtension: 'js'}, 'ng2-activiti-tasklist': { main: './index.js', defaultExtension: 'js'}, 'ng2-alfresco-core': { main: './index.js', defaultExtension: 'js'}, 'ng2-alfresco-datatable': { main: './index.js', defaultExtension: 'js'} diff --git a/ng2-components/ng2-activiti-processlist/karma.conf.js b/ng2-components/ng2-activiti-processlist/karma.conf.js index 1cdd488ff6..3eb9845474 100644 --- a/ng2-components/ng2-activiti-processlist/karma.conf.js +++ b/ng2-components/ng2-activiti-processlist/karma.conf.js @@ -46,7 +46,7 @@ module.exports = function (config) { { pattern: 'node_modules/ng2-alfresco-core/dist/**/*.*', included: false, served: true, watched: false }, { pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.*', included: false, served: true, watched: false }, { pattern: 'node_modules/ng2-activiti-tasklist/dist/**/*.js', included: false, served: true, watched: false }, - { pattern: 'node_modules/ng2-activiti-form/dist/**/*.js', included: false, served: true, watched: false }, + { pattern: 'node_modules/ng2-activiti-form/dist/**/*.*', included: false, served: true, watched: false }, // paths to support debugging with source maps in dev tools {pattern: 'src/**/*.ts', included: false, watched: false}, diff --git a/ng2-components/ng2-activiti-processlist/src/assets/translation.service.mock.ts b/ng2-components/ng2-activiti-processlist/src/assets/translation.service.mock.ts index 023104944a..539b2af021 100644 --- a/ng2-components/ng2-activiti-processlist/src/assets/translation.service.mock.ts +++ b/ng2-components/ng2-activiti-processlist/src/assets/translation.service.mock.ts @@ -16,22 +16,13 @@ */ import { Observable } from 'rxjs/Rx'; -import { EventEmitter } from '@angular/core'; - -export interface LangChangeEvent { - lang: string; - translations: any; -} export class TranslationMock { - public onLangChange: EventEmitter = new EventEmitter(); - public get(key: string|Array, interpolateParams?: Object): Observable { return Observable.of(key); } addTranslationFolder() { - } } diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.css b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.css index 7e9e64291f..8e71bd8c1e 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.css +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.css @@ -9,3 +9,13 @@ .material-icons:hover { color: rgb(255, 152, 0); } + +.mdl-dialog { + width: 400px; +} + +.mdl-textfield.alf-mdl-selectfield label { + color: rgba(0,0,0,.54); + font-size: 12px; + top: 4px; +} diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.html b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.html index f33ad4fb17..d20903ba4d 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.html +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.html @@ -3,8 +3,9 @@

{{'START_PROCESS.DIALOG.TITLE'|translate}}

-
- + @@ -15,9 +16,16 @@
+ +
- +
diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.spec.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.spec.ts new file mode 100644 index 0000000000..9a6d3b2d66 --- /dev/null +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.spec.ts @@ -0,0 +1,143 @@ +/*! + * @license + * Copyright 2016 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 { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; +import { Observable } from 'rxjs/Rx'; +import { ActivitiFormModule } from 'ng2-activiti-form'; +import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; +import { FormService } from 'ng2-activiti-form'; +import { TranslationMock } from './../assets/translation.service.mock'; +import { ActivitiStartProcessButton } from './activiti-start-process.component'; +import { ActivitiProcessService } from '../services/activiti-process.service'; + +describe('ActivitiStartProcessButton', () => { + + let componentHandler: any; + let component: ActivitiStartProcessButton; + let fixture: ComponentFixture; + let processService: ActivitiProcessService; + let formService: FormService; + let getDefinitionsSpy: jasmine.Spy; + let startProcessSpy: jasmine.Spy; + let debugElement: DebugElement; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule, ActivitiFormModule ], + declarations: [ + ActivitiStartProcessButton + ], + providers: [ + { provide: AlfrescoTranslationService, useClass: TranslationMock }, + ActivitiProcessService, + FormService + ] + }).compileComponents(); + })); + + beforeEach(() => { + + fixture = TestBed.createComponent(ActivitiStartProcessButton); + component = fixture.componentInstance; + debugElement = fixture.debugElement; + processService = fixture.debugElement.injector.get(ActivitiProcessService); + formService = fixture.debugElement.injector.get(FormService); + + getDefinitionsSpy = spyOn(processService, 'getProcessDefinitions').and.returnValue(Observable.of([{ + id: 'my:process1', + name: 'My Process 1' + }, { + id: 'my:process2', + name: 'My Process 2' + }])); + startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(Observable.of({ + id: '32323', + name: 'Process' + })); + + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered', + 'upgradeElement' + ]); + window['componentHandler'] = componentHandler; + }); + + it('should display the correct number of processes in the select list', () => { + fixture.detectChanges(); + let selectElement = debugElement.query(By.css('select')); + expect(selectElement.children.length).toBe(3); + }); + + it('should display the correct process def details', (done) => { + fixture.detectChanges(); + fixture.whenStable().then(() => { + let optionEl: HTMLOptionElement = debugElement.queryAll(By.css('select option'))[1].nativeElement; + expect(optionEl.value).toBe('my:process1'); + expect(optionEl.textContent.trim()).toBe('My Process 1'); + done(); + }); + }); + + it('should call service to start process if required fields provided', (done) => { + component.name = 'My new process'; + component.processDefinitionId = 'my:process1'; + component.showDialog(); + fixture.detectChanges(); + component.startProcess(); + fixture.whenStable().then(() => { + expect(startProcessSpy).toHaveBeenCalled(); + done(); + }); + }); + + it('should avoid calling service to start process if required fields NOT provided', (done) => { + component.showDialog(); + fixture.detectChanges(); + component.startProcess(); + fixture.whenStable().then(() => { + expect(startProcessSpy).not.toHaveBeenCalled(); + done(); + }); + }); + + it('should call service to start process with the correct parameters', (done) => { + component.name = 'My new process'; + component.processDefinitionId = 'my:process1'; + component.showDialog(); + fixture.detectChanges(); + component.startProcess(); + fixture.whenStable().then(() => { + expect(startProcessSpy).toHaveBeenCalledWith('my:process1', 'My new process', undefined); + done(); + }); + }); + + it('should indicate start form is missing when process does not have a start form', (done) => { + component.name = 'My new process'; + component.processDefinitionId = 'my:process1'; + component.showDialog(); + fixture.detectChanges(); + component.startProcess(); + fixture.whenStable().then(() => { + expect(component.isStartFormMissingOrValid()).toBe(true); + done(); + }); + }); + +}); diff --git a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.ts b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.ts index d9d7186bfa..71331e2ada 100644 --- a/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.ts +++ b/ng2-components/ng2-activiti-processlist/src/components/activiti-start-process.component.ts @@ -15,11 +15,13 @@ * limitations under the License. */ -import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, Input, OnInit, ViewChild, DebugElement } from '@angular/core'; import { AlfrescoTranslationService } from 'ng2-alfresco-core'; +import { ActivitiStartForm } from 'ng2-activiti-form'; import { ActivitiProcessService } from './../services/activiti-process.service'; declare let componentHandler: any; +declare let dialogPolyfill: any; @Component({ selector: 'activiti-start-process-instance', @@ -33,12 +35,15 @@ export class ActivitiStartProcessButton implements OnInit { appId: string; @ViewChild('dialog') - dialog: any; + dialog: DebugElement; + + @ViewChild('startForm') + startForm: ActivitiStartForm; processDefinitions: any[] = []; name: string; - processDefinition: string; + processDefinitionId: string; constructor(private translate: AlfrescoTranslationService, private activitiProcess: ActivitiProcessService) { @@ -64,15 +69,19 @@ export class ActivitiStartProcessButton implements OnInit { } public showDialog() { - if (this.dialog) { - this.dialog.nativeElement.showModal(); + if (!this.dialog.nativeElement.showModal) { + dialogPolyfill.registerDialog(this.dialog.nativeElement); } + this.dialog.nativeElement.showModal(); } public startProcess() { - if (this.processDefinition && this.name) { - this.activitiProcess.startProcess(this.processDefinition, this.name).subscribe( + if (this.processDefinitionId && this.name) { + let formValues = this.startForm ? this.startForm.form.values : undefined; + this.activitiProcess.startProcess(this.processDefinitionId, this.name, formValues).subscribe( (res: any) => { + this.name = ''; + this.processDefinitionId = ''; this.cancel(); }, (err) => { @@ -83,8 +92,25 @@ export class ActivitiStartProcessButton implements OnInit { } public cancel() { - if (this.dialog) { - this.dialog.nativeElement.close(); - } + this.dialog.nativeElement.close(); + } + + private getSelectedProcess(): any { + return this.processDefinitions.filter((processDefinition) => { + return processDefinition.id === this.processDefinitionId; + })[0]; + } + + hasStartForm() { + let selectedProcessDefinition = this.getSelectedProcess(); + return selectedProcessDefinition && selectedProcessDefinition.hasStartForm; + } + + isStartFormMissingOrValid() { + return !this.startForm || this.startForm.form.isValid; + } + + validateForm() { + return this.processDefinitionId && this.name && this.isStartFormMissingOrValid(); } } diff --git a/ng2-components/ng2-activiti-processlist/src/i18n/en.json b/ng2-components/ng2-activiti-processlist/src/i18n/en.json index 5c45ffab35..2c124caa35 100644 --- a/ng2-components/ng2-activiti-processlist/src/i18n/en.json +++ b/ng2-components/ng2-activiti-processlist/src/i18n/en.json @@ -45,6 +45,7 @@ "TYPE": "Type", "NAME": "Name" }, + "TYPE_PLACEHOLDER": "Choose one...", "ACTION": { "START": "Start", "CANCEL": "Cancel" diff --git a/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts b/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts index ec301c890e..57cc765830 100644 --- a/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts +++ b/ng2-components/ng2-activiti-processlist/src/services/activiti-process.service.ts @@ -226,10 +226,14 @@ export class ActivitiProcessService { .catch(this.handleError); } - startProcess(processDefinitionId: string, name: string) { - let startRequest: any = {}; - startRequest.name = name; - startRequest.processDefinitionId = processDefinitionId; + startProcess(processDefinitionId: string, name: string, startFormValues?: any) { + let startRequest: any = { + name: name, + processDefinitionId: processDefinitionId + }; + if (startFormValues) { + startRequest.values = startFormValues; + } return Observable.fromPromise( this.authService.getAlfrescoApi().activiti.processApi.startNewProcessInstance(startRequest) )