mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
Merge pull request #629 from Alfresco/dev-mromano-591
ECM node to BPM form & BPM form to ECM node #628
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
<div class="activiti-form-viewer" *ngIf="taskId">
|
||||
<activiti-form [taskId]="taskId"></activiti-form>
|
||||
<!--<activiti-form [formName]="'activitiForms:patientFolder'"
|
||||
[saveMetadata]="true"
|
||||
[path]="'/Sites/swsdp/documentLibrary'"
|
||||
[nameNode]="'test'"></activiti-form>-->
|
||||
<!--<activiti-form [nodeId]="'e280be3a-6584-45a1-8bb5-89bfe070262e'"-->
|
||||
<!--[saveMetadata]="true"-->
|
||||
<!--[path]="'/Sites/swsdp/documentLibrary'">-->
|
||||
<!--</activiti-form>-->
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
import { Component, OnInit, OnDestroy, AfterViewChecked } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivitiForm, FormService } from 'ng2-activiti-form';
|
||||
import { ActivitiForm, FormService, EcmModelService, NodeService } from 'ng2-activiti-form';
|
||||
import { Subscription } from 'rxjs/Rx';
|
||||
|
||||
declare let __moduleName: string;
|
||||
@@ -29,7 +29,7 @@ declare var componentHandler;
|
||||
templateUrl: './form-viewer.component.html',
|
||||
styleUrls: ['./form-viewer.component.css'],
|
||||
directives: [ActivitiForm],
|
||||
providers: [FormService]
|
||||
providers: [FormService, EcmModelService, NodeService]
|
||||
})
|
||||
export class FormViewer implements OnInit, OnDestroy, AfterViewChecked {
|
||||
|
||||
|
||||
@@ -78,6 +78,38 @@ Only form definition will be fetched
|
||||
</activiti-form>
|
||||
```
|
||||
|
||||
### Display form definition by ECM nodeId, in this case the metadata of the node are showed in an activiti Form. If there are no form
|
||||
definied in activiti for the type of the node, a new form will be automaticaly created in activiti.
|
||||
|
||||
```html
|
||||
<activiti-form
|
||||
[nodeId]="'e280be3a-6584-45a1-8bb5-89bfe070262e'">
|
||||
</activiti-form>
|
||||
```
|
||||
|
||||
### Display form definition by form name, and store the form field as metadata. The param nameNode is optional.
|
||||
|
||||
```html
|
||||
<activiti-form
|
||||
[formName]="'activitiForms:patientFolder'"
|
||||
[saveMetadata]="true"
|
||||
[path]="'/Sites/swsdp/documentLibrary'"
|
||||
[nameNode]="'test'">
|
||||
</activiti-form>
|
||||
```
|
||||
|
||||
### Display form definition by ECM nodeId, in this case the metadata of the node are showed in an activiti Form, and store the form field
|
||||
as metadata. The param nameNode is optional.
|
||||
|
||||
```html
|
||||
<activiti-form
|
||||
[nodeId]="'e280be3a-6584-45a1-8bb5-89bfe070262e'"
|
||||
[saveMetadata]="true"
|
||||
[path]="'/Sites/swsdp/documentLibrary'"
|
||||
[nameNode]="'test'">
|
||||
</activiti-form>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Properties
|
||||
@@ -95,7 +127,15 @@ The recommended set of properties can be found in the following table:
|
||||
| showSaveButton | boolean | true | Toggle rendering of the `Save` outcome button. |
|
||||
| readOnly | boolean | false | Toggle readonly state of the form. Enforces all form widgets render readonly if enabled. |
|
||||
| showRefreshButton | boolean | true | Toggle rendering of the `Refresh` button. |
|
||||
| saveMetadata | boolean | false | Store the value of the form as metadata. |
|
||||
| path | string | | Path of the folder where to store the metadata. |
|
||||
| nameNode (optional) | string | true | Name to assign to the new node where the metadata are stored. |
|
||||
|
||||
|
||||
*
|
||||
* {path} string - path of the folder where the to store the metadata
|
||||
*
|
||||
* {nameNode} string (optional) - name of the node stored, if not defined the node will be sotred with an uuid as name
|
||||
#### Advanced properties
|
||||
|
||||
The following properties are for complex customisation purposes:
|
||||
|
||||
@@ -18,3 +18,5 @@
|
||||
export * from './src/components/activiti-form.component';
|
||||
export * from './src/services/form.service';
|
||||
export * from './src/components/widgets/index';
|
||||
export * from './src/services/ecm-model.service';
|
||||
export * from './src/services/node.service';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div>
|
||||
<div *ngIf="!hasForm()">
|
||||
<h3 style="text-align: center">Please select a Visit</h3>
|
||||
<h3 style="text-align: center">Please select a Task</h3>
|
||||
</div>
|
||||
<div *ngIf="hasForm()">
|
||||
<div class="mdl-card mdl-shadow--2dp activiti-form-container">
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('ActivitiForm', () => {
|
||||
let visibilityService: WidgetVisibilityService;
|
||||
|
||||
beforeEach(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered'
|
||||
]);
|
||||
visibilityService = jasmine.createSpyObj('WidgetVisibilityService', [
|
||||
@@ -40,8 +40,8 @@ describe('ActivitiForm', () => {
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
|
||||
formService = new FormService(null);
|
||||
formComponent = new ActivitiForm(formService, visibilityService);
|
||||
formService = new FormService(null, null);
|
||||
formComponent = new ActivitiForm(formService, visibilityService, null, null, null);
|
||||
});
|
||||
|
||||
it('should upgrade MDL content on view checked', () => {
|
||||
|
||||
@@ -23,9 +23,10 @@ import {
|
||||
Output,
|
||||
EventEmitter
|
||||
} from '@angular/core';
|
||||
import { MATERIAL_DESIGN_DIRECTIVES } from 'ng2-alfresco-core';
|
||||
|
||||
import { MATERIAL_DESIGN_DIRECTIVES, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
|
||||
import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { NodeService } from './../services/node.service';
|
||||
import { FormModel, FormOutcomeModel, FormValues, FormFieldModel, FormOutcomeEvent } from './widgets/core/index';
|
||||
|
||||
import { TabsWidget } from './widgets/tabs/tabs.widget';
|
||||
@@ -38,19 +39,23 @@ import { WidgetVisibilityService } from './../services/widget-visibility.servic
|
||||
|
||||
/**
|
||||
* @Input
|
||||
* ActivitiForm can show 3 forms searching by 3 type of params:
|
||||
* ActivitiForm can show 4 types of forms searching by 4 type of params:
|
||||
* 1) Form attached to a task passing the {taskId}.
|
||||
*
|
||||
* 2) Form that are only defined with the {formId} (in this case you receive only the form definition and the form will not be
|
||||
* attached to any process, useful in case you want to use ActivitiForm as form designer), in this case you can pass also other 2
|
||||
* parameters:
|
||||
* - {saveOption} as parameter to tell what is the function to call on the save action.
|
||||
* - {data} to fill the form field with some data, the id of the form must to match the name of the field of the provided data object.
|
||||
*
|
||||
* 3) Form that are only defined with the {formName} (in this case you receive only the form definition and the form will not be
|
||||
* attached to any process, useful in case you want to use ActivitiForm as form designer),
|
||||
* in this case you can pass also other 2 parameters:
|
||||
* - {saveOption} as parameter to tell what is the function to call on the save action.
|
||||
* - {data} to fill the form field with some data, the id of the form must to match the name of the field of the provided data object.
|
||||
*
|
||||
* 4) Form that show the metadata of a {nodeId}
|
||||
*
|
||||
* {showTitle} boolean - to hide the title of the form pass false, default true;
|
||||
*
|
||||
* {showRefreshButton} boolean - to hide the refresh button of the form pass false, default true;
|
||||
@@ -59,6 +64,12 @@ import { WidgetVisibilityService } from './../services/widget-visibility.servic
|
||||
*
|
||||
* {showSaveButton} boolean - to hide the save button of the form pass false, default true;
|
||||
*
|
||||
* {saveMetadata} boolean - store the value of the form as metadata, default false;
|
||||
*
|
||||
* {path} string - path of the folder where to store the metadata;
|
||||
*
|
||||
* {nameNode} string (optional) - Name to assign to the new node where the metadata are stored;
|
||||
*
|
||||
* @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.
|
||||
@@ -72,7 +83,7 @@ import { WidgetVisibilityService } from './../services/widget-visibility.servic
|
||||
templateUrl: './activiti-form.component.html',
|
||||
styleUrls: ['./activiti-form.component.css'],
|
||||
directives: [MATERIAL_DESIGN_DIRECTIVES, ContainerWidget, TabsWidget],
|
||||
providers: [FormService, WidgetVisibilityService]
|
||||
providers: [EcmModelService, FormService, WidgetVisibilityService, NodeService]
|
||||
})
|
||||
export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
|
||||
@@ -83,15 +94,27 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
@Input()
|
||||
taskId: string;
|
||||
|
||||
@Input()
|
||||
nodeId: string;
|
||||
|
||||
@Input()
|
||||
formId: string;
|
||||
|
||||
@Input()
|
||||
formName: string;
|
||||
|
||||
@Input()
|
||||
saveMetadata: boolean = false;
|
||||
|
||||
@Input()
|
||||
data: FormValues;
|
||||
|
||||
@Input()
|
||||
path: string;
|
||||
|
||||
@Input()
|
||||
nameNode: string;
|
||||
|
||||
@Input()
|
||||
showTitle: boolean = true;
|
||||
|
||||
@@ -124,7 +147,10 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
debugMode: boolean = false;
|
||||
|
||||
constructor(private formService: FormService,
|
||||
private visibilityService: WidgetVisibilityService) {
|
||||
private visibilityService: WidgetVisibilityService,
|
||||
private authService: AlfrescoAuthenticationService,
|
||||
private ecmModelService: EcmModelService,
|
||||
private nodeService: NodeService) {
|
||||
}
|
||||
|
||||
hasForm(): boolean {
|
||||
@@ -154,7 +180,11 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.loadForm();
|
||||
if (this.nodeId) {
|
||||
this.loadActivitiFormForEcmNode();
|
||||
} else {
|
||||
this.loadForm();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
@@ -208,6 +238,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
|
||||
if (outcome.id === ActivitiForm.CUSTOM_OUTCOME_ID) {
|
||||
this.formSaved.emit(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@@ -275,7 +306,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
.getFormDefinitionById(formId)
|
||||
.subscribe(
|
||||
form => {
|
||||
// console.log('Get Form By definition Id', form);
|
||||
this.formName = form.name;
|
||||
this.form = this.parseForm(form);
|
||||
this.formLoaded.emit(this.form);
|
||||
},
|
||||
@@ -306,7 +337,10 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
this.formService
|
||||
.saveTaskForm(this.form.taskId, this.form.values)
|
||||
.subscribe(
|
||||
() => this.formSaved.emit(this.form),
|
||||
() => {
|
||||
this.formSaved.emit(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
}
|
||||
@@ -317,13 +351,16 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
this.formService
|
||||
.completeTaskForm(this.form.taskId, this.form.values, outcome)
|
||||
.subscribe(
|
||||
() => this.formCompleted.emit(this.form),
|
||||
() => {
|
||||
this.formCompleted.emit(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleError(err: any) {
|
||||
handleError(err: any): any {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
@@ -345,7 +382,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
*/
|
||||
getFormDefinitionOutcomes(form: FormModel): FormOutcomeModel[] {
|
||||
return [
|
||||
new FormOutcomeModel(form, { id: '$custom', name: FormOutcomeModel.SAVE_ACTION, isSystem: true })
|
||||
new FormOutcomeModel(form, {id: '$custom', name: FormOutcomeModel.SAVE_ACTION, isSystem: true})
|
||||
];
|
||||
}
|
||||
|
||||
@@ -354,4 +391,41 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
this.visibilityService.updateVisibilityForForm(field.form);
|
||||
}
|
||||
}
|
||||
|
||||
private loadActivitiFormForEcmNode(): void {
|
||||
this.nodeService.getNodeMetadata(this.nodeId).subscribe(data => {
|
||||
this.data = data.metadata;
|
||||
this.loadFormFromActiviti(data.nodeType);
|
||||
},
|
||||
this.handleError);
|
||||
}
|
||||
|
||||
public loadFormFromActiviti(nodeType: string): any {
|
||||
this.formService.searchFrom(nodeType).subscribe(
|
||||
form => {
|
||||
if (!form) {
|
||||
this.formService.createFormFromNodeType(nodeType).subscribe(formMetadata => {
|
||||
this.loadFormFromFormId(formMetadata.id);
|
||||
});
|
||||
} else {
|
||||
this.loadFormFromFormId(form.id);
|
||||
}
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
}
|
||||
|
||||
private loadFormFromFormId(formId: string) {
|
||||
this.formId = formId;
|
||||
this.loadForm();
|
||||
}
|
||||
|
||||
private storeFormAsMetadata() {
|
||||
if (this.saveMetadata) {
|
||||
this.ecmModelService.createEcmTypeForActivitiForm(this.formName, this.form).subscribe(type => {
|
||||
this.nodeService.createNodeMetadata(type.nodeType || type.entry.prefixedName, EcmModelService.MODEL_NAMESPACE, this.form.values, this.path, this.nameNode);
|
||||
}, this.handleError
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export class FormDefinitionModel {
|
||||
reusable: boolean = false;
|
||||
newVersion: boolean = false;
|
||||
formRepresentation: any;
|
||||
formImageBase64: string = '';
|
||||
|
||||
constructor(id: string, name: any, lastUpdatedByFullName: string, lastUpdated: string, metadata: any) {
|
||||
|
||||
this.formRepresentation = {
|
||||
id: id,
|
||||
name: name,
|
||||
description: '',
|
||||
version: 1,
|
||||
lastUpdatedBy: 1,
|
||||
lastUpdatedByFullName: lastUpdatedByFullName,
|
||||
lastUpdated: lastUpdated,
|
||||
stencilSetId: 0,
|
||||
referenceId: null,
|
||||
formDefinition: {
|
||||
fields: [{
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
fieldType: 'ContainerRepresentation',
|
||||
numberOfColumns: 2,
|
||||
required: false,
|
||||
readOnly: false,
|
||||
sizeX: 2,
|
||||
sizeY: 1,
|
||||
row: -1,
|
||||
col: -1,
|
||||
fields: {'1': this.metadataToFields(metadata)}
|
||||
}],
|
||||
gridsterForm: false,
|
||||
javascriptEvents: [],
|
||||
metadata: {},
|
||||
outcomes: [],
|
||||
className: '',
|
||||
style: '',
|
||||
tabs: [],
|
||||
variables: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private metadataToFields(metadata: any): any[] {
|
||||
let fields = [];
|
||||
if (metadata) {
|
||||
metadata.forEach(function(property) {
|
||||
if (property) {
|
||||
let field = {
|
||||
type: 'text',
|
||||
id: property.name,
|
||||
name: property.name,
|
||||
required: false,
|
||||
readOnly: false,
|
||||
sizeX: 1,
|
||||
sizeY: 1,
|
||||
row: -1,
|
||||
col: -1,
|
||||
colspan: 1,
|
||||
params: {
|
||||
existingColspan: 1,
|
||||
maxColspan: 2
|
||||
},
|
||||
layout: {
|
||||
colspan: 1,
|
||||
row: -1,
|
||||
column: -1
|
||||
}
|
||||
};
|
||||
fields.push(field);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export class NodeMetadata {
|
||||
metadata: any;
|
||||
nodeType: string;
|
||||
|
||||
constructor(metadata: any, nodeType: string) {
|
||||
this.metadata = metadata;
|
||||
this.nodeType = nodeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
/*!
|
||||
* @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 { Injectable } from '@angular/core';
|
||||
import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { Response, Http, Headers, RequestOptions } from '@angular/http';
|
||||
import { FormModel } from '../components/widgets/core/form.model';
|
||||
import { NodeService } from './node.service';
|
||||
|
||||
@Injectable()
|
||||
export class EcmModelService {
|
||||
|
||||
public static MODEL_NAMESPACE: string = 'activitiForms';
|
||||
public static MODEL_NAME: string = 'activitiFormsModel';
|
||||
public static TYPE_MODEL: string = 'cm:folder';
|
||||
|
||||
constructor(private authService: AlfrescoAuthenticationService,
|
||||
private http: Http,
|
||||
public alfrescoSettingsService: AlfrescoSettingsService,
|
||||
private nodeService: NodeService) {
|
||||
}
|
||||
|
||||
public createEcmTypeForActivitiForm(formName: string, form: FormModel): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.seachActivitiEcmModel().subscribe(
|
||||
model => {
|
||||
if (!model) {
|
||||
this.createActivitiEcmModel(formName, form).subscribe(typeForm => {
|
||||
observer.next(typeForm);
|
||||
observer.complete();
|
||||
});
|
||||
} else {
|
||||
this.createFomType(formName, form).subscribe(typeForm => {
|
||||
observer.next(typeForm);
|
||||
observer.complete();
|
||||
});
|
||||
}
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private seachActivitiEcmModel() {
|
||||
return this.getEcmModels().map(function (ecmModels: any) {
|
||||
return ecmModels.list.entries.find(model => model.entry.name === EcmModelService.MODEL_NAME);
|
||||
});
|
||||
}
|
||||
|
||||
private createActivitiEcmModel(formName: string, form: FormModel): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.createEcmModel(EcmModelService.MODEL_NAME, EcmModelService.MODEL_NAMESPACE).subscribe(
|
||||
model => {
|
||||
console.log('model created', model);
|
||||
this.activeEcmModel(EcmModelService.MODEL_NAME).subscribe(
|
||||
modelActive => {
|
||||
console.log('model active', modelActive);
|
||||
this.createEcmTypeWithProperties(formName, form).subscribe(typeCreated => {
|
||||
observer.next(typeCreated);
|
||||
observer.complete();
|
||||
});
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private createFomType(formName: string, form: FormModel): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.searchFormType(formName).subscribe(
|
||||
ecmType => {
|
||||
console.log('custom types', ecmType);
|
||||
if (!ecmType) {
|
||||
this.createEcmTypeWithProperties(formName, form).subscribe(typeCreated => {
|
||||
observer.next(typeCreated);
|
||||
observer.complete();
|
||||
});
|
||||
} else {
|
||||
observer.next(ecmType);
|
||||
observer.complete();
|
||||
}
|
||||
},
|
||||
this.handleError
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public createEcmTypeWithProperties(formName: string, form: FormModel): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.createEcmType(formName, EcmModelService.MODEL_NAME, EcmModelService.TYPE_MODEL).subscribe(
|
||||
typeCreated => {
|
||||
console.log('type Created', typeCreated);
|
||||
this.addPropertyToAType(EcmModelService.MODEL_NAME, formName, form).subscribe(
|
||||
properyAdded => {
|
||||
console.log('property Added', properyAdded);
|
||||
observer.next(typeCreated);
|
||||
observer.complete();
|
||||
},
|
||||
this.handleError);
|
||||
},
|
||||
this.handleError);
|
||||
});
|
||||
}
|
||||
|
||||
public searchFormType(formName: string): Observable<any> {
|
||||
return this.getEcmType(EcmModelService.MODEL_NAME).map(function (customTypes: any) {
|
||||
return customTypes.list.entries.find(type => type.entry.prefixedName === formName);
|
||||
});
|
||||
}
|
||||
|
||||
public activeEcmModel(modelName: string): Observable<any> {
|
||||
let url = `${this.alfrescoSettingsService.ecmHost}/alfresco/api/-default-/private/alfresco/versions/1/cmm/${modelName}?select=status`;
|
||||
let options = this.getRequestOptions();
|
||||
|
||||
|
||||
let body = {status: 'ACTIVE'};
|
||||
|
||||
return this.http
|
||||
.put(url, body, options)
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
public createEcmModel(modelName: string, nameSpace: string): Observable<any> {
|
||||
let url = `${this.alfrescoSettingsService.ecmHost}/alfresco/api/-default-/private/alfresco/versions/1/cmm`;
|
||||
let options = this.getRequestOptions();
|
||||
|
||||
|
||||
let body = {
|
||||
status: 'DRAFT', namespaceUri: modelName, namespacePrefix: nameSpace, name: modelName, description: '', author: ''
|
||||
};
|
||||
|
||||
return this.http
|
||||
.post(url, body, options)
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
public getEcmModels(): Observable<any> {
|
||||
let url = `${this.alfrescoSettingsService.ecmHost}/alfresco/api/-default-/private/alfresco/versions/1/cmm`;
|
||||
let options = this.getRequestOptions();
|
||||
|
||||
return this.http
|
||||
.get(url, options)
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
|
||||
public getEcmType(modelName: string): Observable<any> {
|
||||
let url = `${this.alfrescoSettingsService.ecmHost}/alfresco/api/-default-/private/alfresco/versions/1/cmm/${modelName}/types`;
|
||||
let options = this.getRequestOptions();
|
||||
|
||||
return this.http
|
||||
.get(url, options)
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
public createEcmType(typeName: string, modelName: string, parentType: string): Observable<any> {
|
||||
let name = this.cleanNameType(typeName);
|
||||
let url = `${this.alfrescoSettingsService.ecmHost}/alfresco/api/-default-/private/alfresco/versions/1/cmm/${modelName}/types`;
|
||||
let options = this.getRequestOptions();
|
||||
|
||||
let body = {
|
||||
name: name,
|
||||
parentName: parentType,
|
||||
title: typeName,
|
||||
description: ''
|
||||
};
|
||||
|
||||
return this.http
|
||||
.post(url, body, options)
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
public addPropertyToAType(modelName: string, typeName: string, formFields: any) {
|
||||
let name = this.cleanNameType(typeName);
|
||||
let url = `${this.alfrescoSettingsService.ecmHost}/alfresco/api/-default-/private/alfresco/versions/1/cmm/${modelName}/types/${name}?select=props`;
|
||||
let options = this.getRequestOptions();
|
||||
|
||||
let properties = [];
|
||||
if (formFields && formFields.values) {
|
||||
for (let key in formFields.values) {
|
||||
if (key) {
|
||||
properties.push({
|
||||
name: key,
|
||||
title: key,
|
||||
description: key,
|
||||
dataType: 'd:text',
|
||||
multiValued: false,
|
||||
mandatory: false,
|
||||
mandatoryEnforced: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let body = {
|
||||
name: name,
|
||||
properties: properties
|
||||
};
|
||||
|
||||
return this.http
|
||||
.put(url, body, options)
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
public cleanNameType(name: string): string {
|
||||
let cleanName = name;
|
||||
if (name.indexOf(':') !== -1) {
|
||||
cleanName = name.split(':')[1];
|
||||
}
|
||||
return cleanName.replace(/[^a-zA-Z ]/g, '');
|
||||
}
|
||||
|
||||
public getHeaders(): Headers {
|
||||
return new Headers({
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': this.authService.getTicketEcmBase64()
|
||||
});
|
||||
}
|
||||
|
||||
public getRequestOptions(): RequestOptions {
|
||||
let headers = this.getHeaders();
|
||||
return new RequestOptions({headers: headers});
|
||||
}
|
||||
|
||||
toJson(res: Response) {
|
||||
if (res) {
|
||||
let body = res.json();
|
||||
return body || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
handleError(err: any): any {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,10 @@
|
||||
|
||||
import { it, inject, describe, expect, beforeEach, beforeEachProviders, afterEach } from '@angular/core/testing';
|
||||
import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
|
||||
import { Response, ResponseOptions } from '@angular/http';
|
||||
import { HTTP_PROVIDERS, Response, ResponseOptions } from '@angular/http';
|
||||
import { FormService } from './form.service';
|
||||
import { EcmModelService } from './ecm-model.service';
|
||||
import { NodeService } from './node.service';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
@@ -30,7 +32,10 @@ describe('FormService', () => {
|
||||
return [
|
||||
FormService,
|
||||
AlfrescoSettingsService,
|
||||
AlfrescoAuthenticationService
|
||||
AlfrescoAuthenticationService,
|
||||
EcmModelService,
|
||||
HTTP_PROVIDERS,
|
||||
NodeService
|
||||
];
|
||||
});
|
||||
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Rx';
|
||||
import {AlfrescoAuthenticationService} from 'ng2-alfresco-core';
|
||||
import {FormValues} from './../components/widgets/core/index';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { AlfrescoAuthenticationService } from 'ng2-alfresco-core';
|
||||
import { FormValues } from './../components/widgets/core/index';
|
||||
import { FormDefinitionModel } from '../models/form-definition.model';
|
||||
import { EcmModelService } from './ecm-model.service';
|
||||
|
||||
@Injectable()
|
||||
export class FormService {
|
||||
@@ -26,28 +28,127 @@ export class FormService {
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
constructor(private authService: AlfrescoAuthenticationService) {
|
||||
constructor(private authService: AlfrescoAuthenticationService,
|
||||
private ecmModelService: EcmModelService) {
|
||||
}
|
||||
|
||||
getProcessDefinitions(): Observable<any> {
|
||||
/**
|
||||
* Create a Form with a fields for each metadata properties
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public createFormFromNodeType(formName: string): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.createForm(formName).subscribe(
|
||||
form => {
|
||||
this.ecmModelService.searchFormType(formName).subscribe(
|
||||
customType => {
|
||||
let formDefinitionModel = new FormDefinitionModel(form.id, form.name, form.lastUpdatedByFullName, form.lastUpdated, customType.entry.properties);
|
||||
this.addFieldsNodeTypePropertiesToTheForm(form.id, formDefinitionModel).subscribe(formData => {
|
||||
observer.next(formData);
|
||||
observer.complete();
|
||||
}, this.handleError);
|
||||
},
|
||||
this.handleError);
|
||||
}, this.handleError);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Form
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public createForm(formName: string): Observable<any> {
|
||||
let dataModel = {
|
||||
name: formName,
|
||||
description: '',
|
||||
modelType: 2,
|
||||
stencilSet: 0
|
||||
};
|
||||
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.modelsApi.createModel(dataModel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Fields to A form from a metadata properties
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public addFieldsNodeTypePropertiesToTheForm(formId: string, formDefinitionModel: FormDefinitionModel): Observable<any> {
|
||||
return this.addFieldsToAForm(formId, formDefinitionModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Fileds to A form
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public addFieldsToAForm(formId: string, formModel: FormDefinitionModel): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.editorApi.saveForm(formId, formModel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search For A Form by name
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public searchFrom(name: string): Observable<any> {
|
||||
let opts = {
|
||||
'modelType': 2
|
||||
};
|
||||
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.modelsApi.getModels(opts)).map(function (forms: any) {
|
||||
return forms.data.find(formdata => formdata.name === name);
|
||||
}).catch(this.handleError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get All the forms
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public getForms(): Observable<any> {
|
||||
let opts = {
|
||||
'modelType': 2
|
||||
};
|
||||
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.modelsApi.getModels(opts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Process Definition
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public getProcessDefinitions(): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessDefinitions({}))
|
||||
.map(this.toJsonArray)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getTasks(): Observable<any> {
|
||||
/**
|
||||
* Get All the Tasks
|
||||
* @param taskId Task Id
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public getTasks(): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.taskApi.listTasks({}))
|
||||
.map(this.toJsonArray)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getTask(taskId: string): Observable<any> {
|
||||
/**
|
||||
* Get Task
|
||||
* @param taskId Task Id
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public getTask(taskId: string): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.taskApi.getTask(taskId))
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
saveTaskForm(taskId: string, formValues: FormValues): Observable<any> {
|
||||
/**
|
||||
* Save Task Form
|
||||
* @param taskId Task Id
|
||||
* @param formValues Form Values
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public saveTaskForm(taskId: string, formValues: FormValues): Observable<any> {
|
||||
let body = JSON.stringify({values: formValues});
|
||||
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.taskApi.saveTaskForm(taskId, body))
|
||||
@@ -59,9 +160,9 @@ export class FormService {
|
||||
* @param taskId Task Id
|
||||
* @param formValues Form Values
|
||||
* @param outcome Form Outcome
|
||||
* @returns {any}
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
completeTaskForm(taskId: string, formValues: FormValues, outcome?: string): Observable<any> {
|
||||
public completeTaskForm(taskId: string, formValues: FormValues, outcome?: string): Observable<any> {
|
||||
let data: any = {values: formValues};
|
||||
if (outcome) {
|
||||
data.outcome = outcome;
|
||||
@@ -72,13 +173,23 @@ export class FormService {
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getTaskForm(taskId: string): Observable<any> {
|
||||
/**
|
||||
* Get Form related to a taskId
|
||||
* @param taskId Task Id
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public getTaskForm(taskId: string): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.taskApi.getTaskForm(taskId))
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getFormDefinitionById(formId: string): Observable<any> {
|
||||
/**
|
||||
* Get Form Definition
|
||||
* @param formId Form Id
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
public getFormDefinitionById(formId: string): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.editorApi.getForm(formId))
|
||||
.map(this.toJson)
|
||||
.catch(this.handleError);
|
||||
@@ -89,7 +200,7 @@ export class FormService {
|
||||
* @param name
|
||||
* @returns {Promise<T>|Promise<ErrorObservable>}
|
||||
*/
|
||||
getFormDefinitionByName(name: string): Observable<any> {
|
||||
public getFormDefinitionByName(name: string): Observable<any> {
|
||||
let opts = {
|
||||
'filter': 'myReusableForms',
|
||||
'filterText': name,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*!
|
||||
* @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 { Injectable } from '@angular/core';
|
||||
import { AlfrescoAuthenticationService } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { NodeMetadata } from '../models/node-metadata.model';
|
||||
|
||||
@Injectable()
|
||||
export class NodeService {
|
||||
|
||||
constructor(private authService: AlfrescoAuthenticationService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get All the metadata and the nodeType for a nodeId cleaned by the prefix
|
||||
* @param nodeId Node Id
|
||||
* @returns NodeMetadata
|
||||
*/
|
||||
public getNodeMetadata(nodeId: string): Observable<NodeMetadata> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().nodes.getNodeInfo(nodeId)).map(this.cleanMetadataFromSemicolon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Node from form metadata
|
||||
* @param path path
|
||||
* @param nodeType node type
|
||||
* @param nameSpace namespace node
|
||||
* @param data data to store
|
||||
* @returns NodeMetadata
|
||||
*/
|
||||
public createNodeMetadata(nodeType: string, nameSpace: any, data: any, path: string, name?: string): Observable<any> {
|
||||
let properties = {};
|
||||
for (let key in data) {
|
||||
if (data[key]) {
|
||||
properties[nameSpace + ':' + key] = data[key];
|
||||
}
|
||||
}
|
||||
|
||||
return this.createNode(name || this.generateUuid(), nodeType, properties, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Node from form metadata
|
||||
* @param name path
|
||||
* @param nodeType node type
|
||||
* @param properties namespace node
|
||||
* @param path path
|
||||
* @returns NodeMetadata
|
||||
*/
|
||||
public createNode(name: string, nodeType: string, properties: any, path: string): Observable<any> {
|
||||
let body = {
|
||||
name: name,
|
||||
nodeType: nodeType,
|
||||
properties: properties,
|
||||
relativePath: path
|
||||
};
|
||||
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().nodes.addNode('-root-', body, {}));
|
||||
}
|
||||
|
||||
private generateUuid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
private cleanMetadataFromSemicolon(data: any): NodeMetadata {
|
||||
let metadata = {};
|
||||
|
||||
if (data && data.properties) {
|
||||
for (let key in data.properties) {
|
||||
if (key) {
|
||||
metadata [key.split(':')[1]] = data.properties[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new NodeMetadata(metadata, data.nodeType);
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,9 @@ export class AlfrescoSettingsService {
|
||||
|
||||
private providers: string = 'ALL'; // ECM, BPM , ALL
|
||||
|
||||
bpmHostSubject: Subject<string> = new Subject<string>();
|
||||
ecmHostSubject: Subject<string> = new Subject<string>();
|
||||
providerSubject: Subject<string> = new Subject<string>();
|
||||
public bpmHostSubject: Subject<string> = new Subject<string>();
|
||||
public ecmHostSubject: Subject<string> = new Subject<string>();
|
||||
public providerSubject: Subject<string> = new Subject<string>();
|
||||
|
||||
public get ecmHost(): string {
|
||||
return this._ecmHost;
|
||||
|
||||
Reference in New Issue
Block a user