mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-02 17:35:08 +00:00
Merge pull request #1012 from Alfresco/dev-wabson-730
Display start forms in Start Process dialog
This commit is contained in:
commit
7236bf1da9
@ -19,6 +19,7 @@ import { NgModule, ModuleWithProviders } from '@angular/core';
|
|||||||
import { CoreModule } from 'ng2-alfresco-core';
|
import { CoreModule } from 'ng2-alfresco-core';
|
||||||
|
|
||||||
import { ActivitiForm } from './src/components/activiti-form.component';
|
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 { FormService } from './src/services/form.service';
|
||||||
import { EcmModelService } from './src/services/ecm-model.service';
|
import { EcmModelService } from './src/services/ecm-model.service';
|
||||||
import { NodeService } from './src/services/node.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';
|
import { WIDGET_DIRECTIVES } from './src/components/widgets/index';
|
||||||
|
|
||||||
export * from './src/components/activiti-form.component';
|
export * from './src/components/activiti-form.component';
|
||||||
|
export * from './src/components/activiti-start-form.component';
|
||||||
export * from './src/services/form.service';
|
export * from './src/services/form.service';
|
||||||
export * from './src/components/widgets/index';
|
export * from './src/components/widgets/index';
|
||||||
export * from './src/services/ecm-model.service';
|
export * from './src/services/ecm-model.service';
|
||||||
@ -35,6 +37,7 @@ export * from './src/services/node.service';
|
|||||||
|
|
||||||
export const ACTIVITI_FORM_DIRECTIVES: any[] = [
|
export const ACTIVITI_FORM_DIRECTIVES: any[] = [
|
||||||
ActivitiForm,
|
ActivitiForm,
|
||||||
|
ActivitiStartForm,
|
||||||
...WIDGET_DIRECTIVES
|
...WIDGET_DIRECTIVES
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -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<string>, interpolateParams?: Object): Observable<string|any> {
|
||||||
|
return Observable.of(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTranslationFolder() {
|
||||||
|
}
|
||||||
|
}
|
@ -145,7 +145,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
|||||||
|
|
||||||
debugMode: boolean = false;
|
debugMode: boolean = false;
|
||||||
|
|
||||||
constructor(private formService: FormService,
|
constructor(protected formService: FormService,
|
||||||
private visibilityService: WidgetVisibilityService,
|
private visibilityService: WidgetVisibilityService,
|
||||||
private ecmModelService: EcmModelService,
|
private ecmModelService: EcmModelService,
|
||||||
private nodeService: NodeService) {
|
private nodeService: NodeService) {
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
<div>
|
||||||
|
<div *ngIf="hasForm()">
|
||||||
|
<div class="mdl-card mdl-shadow--2dp activiti-form-container">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<i class="material-icons">{{ form.isValid ? 'event_available' : 'event_busy' }}</i>
|
||||||
|
<h2 *ngIf="isTitleEnabled()" class="mdl-card__title-text">{{form.taskName}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__media">
|
||||||
|
<div *ngIf="form.hasTabs()">
|
||||||
|
<tabs-widget [tabs]="form.tabs" (formTabChanged)="checkVisibility($event);"></tabs-widget>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
||||||
|
<container-widget *ngFor="let field of form.fields" [content]="field" (formValueChanged)="checkVisibility($event);"></container-widget>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="showOutcomeButtons && form.hasOutcomes()" class="mdl-card__actions mdl-card--border" #outcomesContainer>
|
||||||
|
<button *ngFor="let outcome of form.outcomes"
|
||||||
|
alfresco-mdl-button
|
||||||
|
[disabled]="!isOutcomeButtonEnabled(outcome)"
|
||||||
|
[class.mdl-button--colored]="!outcome.isSystem"
|
||||||
|
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome)"
|
||||||
|
(click)="onOutcomeClicked(outcome, $event)">
|
||||||
|
{{outcome.name}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="showRefreshButton" class="mdl-card__menu" >
|
||||||
|
<button (click)="onRefreshClicked()"
|
||||||
|
class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
|
||||||
|
<i class="material-icons">refresh</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -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<ActivitiStartForm>;
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -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) {
|
||||||
|
}
|
||||||
|
}
|
7
ng2-components/ng2-activiti-form/src/i18n/en.json
Normal file
7
ng2-components/ng2-activiti-form/src/i18n/en.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"FORM": {
|
||||||
|
"START_FORM": {
|
||||||
|
"TITLE": "Start Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ declare let jasmine: any;
|
|||||||
|
|
||||||
describe('FormService', () => {
|
describe('FormService', () => {
|
||||||
|
|
||||||
let responseBody: any, service: FormService;
|
let responseBody: any, service: FormService, apiService: AlfrescoApiService;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@ -44,6 +44,7 @@ describe('FormService', () => {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
service = TestBed.get(FormService);
|
service = TestBed.get(FormService);
|
||||||
|
apiService = TestBed.get(AlfrescoApiService);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
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', () => {
|
it('should not get form id from response', () => {
|
||||||
let response = new Response(new ResponseOptions({body: null}));
|
let response = new Response(new ResponseOptions({body: null}));
|
||||||
expect(service.getFormId(response)).toBeNull();
|
expect(service.getFormId(response)).toBeNull();
|
||||||
|
@ -206,6 +206,18 @@ export class FormService {
|
|||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get start form definition for a given process
|
||||||
|
* @param processId Process definition ID
|
||||||
|
* @returns {Observable<any>}
|
||||||
|
*/
|
||||||
|
getStartFormDefinition(processId: string): Observable<any> {
|
||||||
|
return Observable.fromPromise(
|
||||||
|
this.apiService.getInstance().activiti.processApi.getProcessDefinitionStartForm(processId))
|
||||||
|
.map(this.toJson)
|
||||||
|
.catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
getRestFieldValues(taskId: string, field: string): Observable<any> {
|
getRestFieldValues(taskId: string, field: string): Observable<any> {
|
||||||
let alfrescoApi = this.apiService.getInstance();
|
let alfrescoApi = this.apiService.getInstance();
|
||||||
return Observable.fromPromise(alfrescoApi.activiti.taskApi.getRestFieldValues(taskId, field));
|
return Observable.fromPromise(alfrescoApi.activiti.taskApi.getRestFieldValues(taskId, field));
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
import { CoreModule } from 'ng2-alfresco-core';
|
import { CoreModule } from 'ng2-alfresco-core';
|
||||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||||
|
import { ActivitiFormModule } from 'ng2-activiti-form';
|
||||||
import { ActivitiTaskListModule } from 'ng2-activiti-tasklist';
|
import { ActivitiTaskListModule } from 'ng2-activiti-tasklist';
|
||||||
|
|
||||||
import { ActivitiProcessInstanceListComponent } from './src/components/activiti-processlist.component';
|
import { ActivitiProcessInstanceListComponent } from './src/components/activiti-processlist.component';
|
||||||
@ -54,6 +55,7 @@ export const ACTIVITI_PROCESSLIST_PROVIDERS: [any] = [
|
|||||||
imports: [
|
imports: [
|
||||||
CoreModule,
|
CoreModule,
|
||||||
DataTableModule,
|
DataTableModule,
|
||||||
|
ActivitiFormModule,
|
||||||
ActivitiTaskListModule
|
ActivitiTaskListModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -54,6 +54,7 @@ var map = {
|
|||||||
'ng2-translate': 'npm:ng2-translate',
|
'ng2-translate': 'npm:ng2-translate',
|
||||||
|
|
||||||
'alfresco-js-api': 'npm:alfresco-js-api/dist',
|
'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-activiti-tasklist': 'npm:ng2-activiti-tasklist/dist',
|
||||||
'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist',
|
'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist',
|
||||||
'ng2-alfresco-datatable': 'npm:ng2-alfresco-datatable/dist'
|
'ng2-alfresco-datatable': 'npm:ng2-alfresco-datatable/dist'
|
||||||
@ -65,6 +66,7 @@ var packages = {
|
|||||||
'ng2-translate': { defaultExtension: 'js' },
|
'ng2-translate': { defaultExtension: 'js' },
|
||||||
|
|
||||||
'alfresco-js-api': { main: './alfresco-js-api.js', 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-activiti-tasklist': { main: './index.js', defaultExtension: 'js'},
|
||||||
'ng2-alfresco-core': { main: './index.js', defaultExtension: 'js'},
|
'ng2-alfresco-core': { main: './index.js', defaultExtension: 'js'},
|
||||||
'ng2-alfresco-datatable': { main: './index.js', defaultExtension: 'js'}
|
'ng2-alfresco-datatable': { main: './index.js', defaultExtension: '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-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-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-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
|
// paths to support debugging with source maps in dev tools
|
||||||
{pattern: 'src/**/*.ts', included: false, watched: false},
|
{pattern: 'src/**/*.ts', included: false, watched: false},
|
||||||
|
@ -16,22 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
import { EventEmitter } from '@angular/core';
|
|
||||||
|
|
||||||
export interface LangChangeEvent {
|
|
||||||
lang: string;
|
|
||||||
translations: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TranslationMock {
|
export class TranslationMock {
|
||||||
|
|
||||||
public onLangChange: EventEmitter<LangChangeEvent> = new EventEmitter<LangChangeEvent>();
|
|
||||||
|
|
||||||
public get(key: string|Array<string>, interpolateParams?: Object): Observable<string|any> {
|
public get(key: string|Array<string>, interpolateParams?: Object): Observable<string|any> {
|
||||||
return Observable.of(key);
|
return Observable.of(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTranslationFolder() {
|
addTranslationFolder() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,3 +9,13 @@
|
|||||||
.material-icons:hover {
|
.material-icons:hover {
|
||||||
color: rgb(255, 152, 0);
|
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;
|
||||||
|
}
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
<dialog class="mdl-dialog" #dialog>
|
<dialog class="mdl-dialog" #dialog>
|
||||||
<h4 class="mdl-dialog__title">{{'START_PROCESS.DIALOG.TITLE'|translate}}</h4>
|
<h4 class="mdl-dialog__title">{{'START_PROCESS.DIALOG.TITLE'|translate}}</h4>
|
||||||
<div class="mdl-dialog__content">
|
<div class="mdl-dialog__content">
|
||||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
<div class="mdl-textfield mdl-js-textfield alf-mdl-selectfield">
|
||||||
<select name="processDefinition" [(ngModel)]="processDefinition" id="processDefinition">
|
<select name="processDefinition" [(ngModel)]="processDefinitionId" id="processDefinition">
|
||||||
|
<option value="" selected="selected">{{'START_PROCESS.DIALOG.TYPE_PLACEHOLDER'|translate}}</option>
|
||||||
<option *ngFor="let processDef of processDefinitions" [value]="processDef.id">
|
<option *ngFor="let processDef of processDefinitions" [value]="processDef.id">
|
||||||
{{processDef.name}}
|
{{processDef.name}}
|
||||||
</option>
|
</option>
|
||||||
@ -15,9 +16,16 @@
|
|||||||
<input class="mdl-textfield__input" type="text" [(ngModel)]="name" id="processName" />
|
<input class="mdl-textfield__input" type="text" [(ngModel)]="name" id="processName" />
|
||||||
<label class="mdl-textfield__label" for="processName">{{'START_PROCESS.DIALOG.LABEL.NAME'|translate}}</label>
|
<label class="mdl-textfield__label" for="processName">{{'START_PROCESS.DIALOG.LABEL.NAME'|translate}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
<activiti-start-form *ngIf="hasStartForm()" [processDefinitionId]="processDefinitionId"
|
||||||
|
(formSaved)='onFormSaved($event)'
|
||||||
|
(formCompleted)='onFormCompleted($event)'
|
||||||
|
(formLoaded)='onFormLoaded($event)'
|
||||||
|
(onError)='onFormError($event)'
|
||||||
|
#startForm>
|
||||||
|
</activiti-start-form>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-dialog__actions">
|
<div class="mdl-dialog__actions">
|
||||||
<button type="button" (click)="startProcess()" class="mdl-button">{{'START_PROCESS.DIALOG.ACTION.START'|translate}}</button>
|
<button type="button" [disabled]="!validateForm()" (click)="startProcess()" class="mdl-button">{{'START_PROCESS.DIALOG.ACTION.START'|translate}}</button>
|
||||||
<button type="button" (click)="cancel()" class="mdl-button close">{{'START_PROCESS.DIALOG.ACTION.CANCEL'|translate}}</button>
|
<button type="button" (click)="cancel()" class="mdl-button close">{{'START_PROCESS.DIALOG.ACTION.CANCEL'|translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
@ -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<ActivitiStartProcessButton>;
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -15,11 +15,13 @@
|
|||||||
* limitations under the License.
|
* 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 { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||||
|
import { ActivitiStartForm } from 'ng2-activiti-form';
|
||||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||||
|
|
||||||
declare let componentHandler: any;
|
declare let componentHandler: any;
|
||||||
|
declare let dialogPolyfill: any;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'activiti-start-process-instance',
|
selector: 'activiti-start-process-instance',
|
||||||
@ -33,12 +35,15 @@ export class ActivitiStartProcessButton implements OnInit {
|
|||||||
appId: string;
|
appId: string;
|
||||||
|
|
||||||
@ViewChild('dialog')
|
@ViewChild('dialog')
|
||||||
dialog: any;
|
dialog: DebugElement;
|
||||||
|
|
||||||
|
@ViewChild('startForm')
|
||||||
|
startForm: ActivitiStartForm;
|
||||||
|
|
||||||
processDefinitions: any[] = [];
|
processDefinitions: any[] = [];
|
||||||
|
|
||||||
name: string;
|
name: string;
|
||||||
processDefinition: string;
|
processDefinitionId: string;
|
||||||
|
|
||||||
constructor(private translate: AlfrescoTranslationService,
|
constructor(private translate: AlfrescoTranslationService,
|
||||||
private activitiProcess: ActivitiProcessService) {
|
private activitiProcess: ActivitiProcessService) {
|
||||||
@ -64,15 +69,19 @@ export class ActivitiStartProcessButton implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public showDialog() {
|
public showDialog() {
|
||||||
if (this.dialog) {
|
if (!this.dialog.nativeElement.showModal) {
|
||||||
this.dialog.nativeElement.showModal();
|
dialogPolyfill.registerDialog(this.dialog.nativeElement);
|
||||||
}
|
}
|
||||||
|
this.dialog.nativeElement.showModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
public startProcess() {
|
public startProcess() {
|
||||||
if (this.processDefinition && this.name) {
|
if (this.processDefinitionId && this.name) {
|
||||||
this.activitiProcess.startProcess(this.processDefinition, this.name).subscribe(
|
let formValues = this.startForm ? this.startForm.form.values : undefined;
|
||||||
|
this.activitiProcess.startProcess(this.processDefinitionId, this.name, formValues).subscribe(
|
||||||
(res: any) => {
|
(res: any) => {
|
||||||
|
this.name = '';
|
||||||
|
this.processDefinitionId = '';
|
||||||
this.cancel();
|
this.cancel();
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
@ -83,8 +92,25 @@ export class ActivitiStartProcessButton implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public cancel() {
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
"TYPE": "Type",
|
"TYPE": "Type",
|
||||||
"NAME": "Name"
|
"NAME": "Name"
|
||||||
},
|
},
|
||||||
|
"TYPE_PLACEHOLDER": "Choose one...",
|
||||||
"ACTION": {
|
"ACTION": {
|
||||||
"START": "Start",
|
"START": "Start",
|
||||||
"CANCEL": "Cancel"
|
"CANCEL": "Cancel"
|
||||||
|
@ -226,10 +226,14 @@ export class ActivitiProcessService {
|
|||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
startProcess(processDefinitionId: string, name: string) {
|
startProcess(processDefinitionId: string, name: string, startFormValues?: any) {
|
||||||
let startRequest: any = {};
|
let startRequest: any = {
|
||||||
startRequest.name = name;
|
name: name,
|
||||||
startRequest.processDefinitionId = processDefinitionId;
|
processDefinitionId: processDefinitionId
|
||||||
|
};
|
||||||
|
if (startFormValues) {
|
||||||
|
startRequest.values = startFormValues;
|
||||||
|
}
|
||||||
return Observable.fromPromise(
|
return Observable.fromPromise(
|
||||||
this.authService.getAlfrescoApi().activiti.processApi.startNewProcessInstance(startRequest)
|
this.authService.getAlfrescoApi().activiti.processApi.startNewProcessInstance(startRequest)
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user