mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
Merge branch 'development' into dev-denys-dts
# Conflicts: # demo-shell-ng2/systemjs.config.js # ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts # ng2-components/ng2-alfresco-upload/src/services/upload.service.ts # ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.spec.t s # ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.ts
This commit is contained in:
commit
c037b91c9c
10
.travis.yml
10
.travis.yml
@ -28,8 +28,8 @@ env:
|
||||
- MODULE=ng2-alfresco-viewer
|
||||
- MODULE=ng2-alfresco-webscript
|
||||
- MODULE=ng2-activiti-form
|
||||
- MODULE=ng2-activiti-processlist
|
||||
- MODULE=ng2-activiti-tasklist
|
||||
- MODULE=ng2-activiti-processlist
|
||||
|
||||
before_script:
|
||||
- if ([ "$MODULE" != "ng2-alfresco-core" ]); then
|
||||
@ -38,9 +38,12 @@ before_script:
|
||||
- if ([ "$MODULE" == "ng2-alfresco-documentlist" ] || [ "$MODULE" == "ng2-alfresco-webscript" ] || [ "$MODULE" == "ng2-activiti-processlist" ] || [ "$MODULE" == "ng2-activiti-tasklist" ]); then
|
||||
(cd ng2-components/ng2-alfresco-datatable; npm link ng2-alfresco-core; npm install; npm link);
|
||||
fi
|
||||
- if ([ "$MODULE" == "ng2-activiti-tasklist" ]); then
|
||||
- if ([ "$MODULE" == "ng2-activiti-tasklist" ] || [ "$MODULE" == "ng2-activiti-processlist" ]); then
|
||||
(cd ng2-components/ng2-activiti-form; npm link ng2-alfresco-core; npm install; npm link);
|
||||
fi
|
||||
- if ([ "$MODULE" == "ng2-activiti-processlist" ]); then
|
||||
(cd ng2-components/ng2-activiti-tasklist; npm link ng2-alfresco-core; npm link ng2-alfresco-datatable; npm link ng2-activiti-form; npm install; npm link);
|
||||
fi
|
||||
- cd ng2-components/$MODULE;
|
||||
- if ([ "$MODULE" != "ng2-alfresco-core" ]); then
|
||||
npm link ng2-alfresco-core;
|
||||
@ -51,6 +54,9 @@ before_script:
|
||||
- if ([ "$MODULE" == "ng2-activiti-tasklist" ]); then
|
||||
npm link ng2-activiti-form;
|
||||
fi
|
||||
- if ([ "$MODULE" == "ng2-activiti-processlist" ]); then
|
||||
npm link ng2-activiti-tasklist;
|
||||
fi
|
||||
- npm install;
|
||||
- npm run travis
|
||||
- ls -ltrh ./node_modules/
|
||||
|
@ -52,6 +52,8 @@ The following is a list of some of the components that you can use when building
|
||||
- [Core library](ng2-components/ng2-alfresco-core/README.md)
|
||||
- [DataTable](ng2-components/ng2-alfresco-datatable/README.md)
|
||||
- [DocumentList](ng2-components/ng2-alfresco-documentlist/README.md)
|
||||
- Activiti [ProcessList](ng2-components/ng2-activiti-processlist/README.md) and [TaskList](ng2-components/ng2-activiti-tasklist/README.md)
|
||||
- [Activiti Form](ng2-components/ng2-activiti-form/README.md)
|
||||
- [Viewer](ng2-components/ng2-alfresco-viewer/README.md)
|
||||
- [Login](ng2-components/ng2-alfresco-login/README.md)
|
||||
- [Upload](ng2-components/ng2-alfresco-upload/README.md)
|
||||
|
@ -27,6 +27,8 @@ install:
|
||||
- IF %COMPONENT_NAME% NEQ ng2-alfresco-core (cd ng2-components/ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-alfresco-documentlist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-activiti-form && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-activiti-tasklist && npm link ng2-alfresco-core && npm link ng2-alfresco-datatable && npm link ng2-activiti-form && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (cd ng2-components/ng2-activiti-form && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
- IF %COMPONENT_NAME% EQU ng2-alfresco-webscript (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
|
||||
@ -34,6 +36,7 @@ install:
|
||||
- IF %COMPONENT_NAME% NEQ ng2-alfresco-core (npm link ng2-alfresco-core)
|
||||
- IF %COMPONENT_NAME% EQU ng2-alfresco-documentlist (npm link ng2-alfresco-datatable)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (npm link ng2-alfresco-datatable)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (npm link ng2-activiti-tasklist)
|
||||
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (npm link ng2-alfresco-datatable && npm link ng2-activiti-form)
|
||||
- IF %COMPONENT_NAME% EQU ng2-alfresco-webscript (npm link ng2-alfresco-datatable)
|
||||
- npm install
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
AboutComponent,
|
||||
FormViewer
|
||||
} from './components/index';
|
||||
import { FormNodeViewer } from './components/activiti/form-node-viewer.component';
|
||||
|
||||
export const routes: RouterConfig = [
|
||||
{ path: 'home', component: FilesComponent },
|
||||
@ -39,6 +40,7 @@ export const routes: RouterConfig = [
|
||||
{ path: 'search', component: SearchComponent },
|
||||
{ path: 'activiti', component: ActivitiDemoComponent },
|
||||
{ path: 'activiti/tasks/:id', component: FormViewer },
|
||||
{ path: 'activiti/tasksnode/:id', component: FormNodeViewer },
|
||||
{ path: 'webscript', component: WebscriptComponent },
|
||||
{ path: 'about', component: AboutComponent }
|
||||
];
|
||||
|
@ -13,16 +13,17 @@
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
|
||||
<span>Task Filters</span>
|
||||
<activiti-filters (filterClick)="onFilterClick($event)"></activiti-filters>
|
||||
<activiti-filters (filterClick)="onTaskFilterClick($event)"></activiti-filters>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--3-col task-column mdl-shadow--2dp">
|
||||
<span>Task List</span>
|
||||
<activiti-tasklist *ngIf="isTaskListSelected()" [taskFilter]="taskFilter" [schemaColumn]="schemaColumn"
|
||||
(rowClick)="onRowClick($event)" #activititasklist></activiti-tasklist>
|
||||
<activiti-tasklist *ngIf="isTaskListSelected()" [taskFilter]="taskFilter" [schemaColumn]="taskSchemaColumns"
|
||||
(rowClick)="onTaskRowClick($event)" #activititasklist></activiti-tasklist>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--7-col task-column mdl-shadow--2dp">
|
||||
<span>Task Details</span>
|
||||
<activiti-task-details [taskId]="currentTaskId" #activitidetails></activiti-task-details>
|
||||
<activiti-task-details [taskId]="currentTaskId" (formCompleted)="onFormCompleted($event)"
|
||||
#activitidetails></activiti-task-details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -33,12 +34,17 @@
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--2-col task-column">
|
||||
<span>Process Filters</span>
|
||||
<activiti-start-process [appId]="appId"></activiti-start-process>
|
||||
<activiti-process-filters (filterClick)="onProcessFilterClick($event)"></activiti-process-filters>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--3-col task-column">
|
||||
<span>Process List</span>
|
||||
<activiti-process-instance-list [filter]="processFilter" [schemaColumn]="processSchemaColumns"
|
||||
(rowClick)="onProcessRowClick($event)" #activitiprocesslist></activiti-process-instance-list>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--7-col task-column">
|
||||
<span>Process Details</span>
|
||||
<activiti-process-instance-details [processInstanceId]="currentProcessInstanceId" (taskFormCompleted)="taskFormCompleted()" (processCancelled)="processCancelled()" #activitiprocessdetails></activiti-process-instance-details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,8 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, AfterViewChecked, ViewChild } from '@angular/core';
|
||||
import { Component, AfterViewChecked, ViewChild, Input } from '@angular/core';
|
||||
import { ALFRESCO_TASKLIST_DIRECTIVES } from 'ng2-activiti-tasklist';
|
||||
import { ACTIVITI_PROCESSLIST_DIRECTIVES } from 'ng2-activiti-processlist';
|
||||
import { ActivitiForm } from 'ng2-activiti-form';
|
||||
|
||||
declare let __moduleName: string;
|
||||
@ -27,7 +28,7 @@ declare var componentHandler;
|
||||
selector: 'activiti-demo',
|
||||
templateUrl: './activiti-demo.component.html',
|
||||
styleUrls: ['./activiti-demo.component.css'],
|
||||
directives: [ALFRESCO_TASKLIST_DIRECTIVES, ActivitiForm]
|
||||
directives: [ALFRESCO_TASKLIST_DIRECTIVES, ACTIVITI_PROCESSLIST_DIRECTIVES, ActivitiForm]
|
||||
})
|
||||
export class ActivitiDemoComponent implements AfterViewChecked {
|
||||
|
||||
@ -39,11 +40,23 @@ export class ActivitiDemoComponent implements AfterViewChecked {
|
||||
@ViewChild('activititasklist')
|
||||
activititasklist: any;
|
||||
|
||||
currentTaskId: string;
|
||||
@ViewChild('activitiprocesslist')
|
||||
activitiprocesslist: any;
|
||||
|
||||
schemaColumn: any [] = [];
|
||||
@ViewChild('activitiprocessdetails')
|
||||
activitiprocessdetails: any;
|
||||
|
||||
currentTaskId: string;
|
||||
currentProcessInstanceId: string;
|
||||
|
||||
taskSchemaColumns: any [] = [];
|
||||
processSchemaColumns: any [] = [];
|
||||
|
||||
taskFilter: any;
|
||||
processFilter: any;
|
||||
|
||||
@Input()
|
||||
appId: string;
|
||||
|
||||
setChoice($event) {
|
||||
this.currentChoice = $event.target.value;
|
||||
@ -58,23 +71,50 @@ export class ActivitiDemoComponent implements AfterViewChecked {
|
||||
}
|
||||
|
||||
constructor() {
|
||||
console.log('Activiti demo component');
|
||||
this.schemaColumn = [
|
||||
this.taskSchemaColumns = [
|
||||
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}
|
||||
// {type: 'text', key: 'created', title: 'Created', sortable: true}
|
||||
];
|
||||
this.processSchemaColumns = [
|
||||
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}
|
||||
];
|
||||
}
|
||||
|
||||
onFilterClick(event: any) {
|
||||
onTaskFilterClick(event: any) {
|
||||
this.taskFilter = event;
|
||||
this.activititasklist.load(this.taskFilter);
|
||||
}
|
||||
|
||||
onRowClick(taskId) {
|
||||
onProcessFilterClick(event: any) {
|
||||
this.processFilter = event.filter;
|
||||
this.activitiprocesslist.load(this.processFilter);
|
||||
}
|
||||
|
||||
onTaskRowClick(taskId) {
|
||||
this.currentTaskId = taskId;
|
||||
this.activitidetails.loadDetails(this.currentTaskId);
|
||||
}
|
||||
|
||||
onProcessRowClick(processInstanceId) {
|
||||
this.currentProcessInstanceId = processInstanceId;
|
||||
this.activitiprocessdetails.load(this.currentProcessInstanceId);
|
||||
}
|
||||
|
||||
processCancelled(data: any) {
|
||||
this.currentProcessInstanceId = null;
|
||||
this.activitiprocesslist.reload();
|
||||
}
|
||||
|
||||
taskFormCompleted(data: any) {
|
||||
this.activitiprocesslist.reload();
|
||||
}
|
||||
|
||||
onFormCompleted(form) {
|
||||
this.activititasklist.load(this.taskFilter);
|
||||
this.currentTaskId = null;
|
||||
this.activitidetails.loadDetails(this.currentTaskId);
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
// workaround for MDL issues with dynamic components
|
||||
if (componentHandler) {
|
||||
|
@ -0,0 +1,3 @@
|
||||
.activiti-form-viewer {
|
||||
margin: 10px;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<div class="activiti-form-viewer" *ngIf="nodeId">
|
||||
<activiti-form [nodeId]="nodeId"
|
||||
[saveMetadata]="true"
|
||||
[path]="'/Sites/swsdp/documentLibrary'">
|
||||
</activiti-form>
|
||||
</div>
|
@ -0,0 +1,62 @@
|
||||
/*!
|
||||
* @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, OnDestroy, AfterViewChecked } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivitiForm, FormService, EcmModelService, NodeService } from 'ng2-activiti-form';
|
||||
import { Subscription } from 'rxjs/Rx';
|
||||
|
||||
declare let __moduleName: string;
|
||||
declare var componentHandler;
|
||||
|
||||
@Component({
|
||||
moduleId: __moduleName,
|
||||
selector: 'form-node-viewer',
|
||||
templateUrl: './form-node-viewer.component.html',
|
||||
styleUrls: ['./form-node-viewer.component.css'],
|
||||
directives: [ActivitiForm],
|
||||
providers: [FormService, EcmModelService, NodeService]
|
||||
})
|
||||
export class FormNodeViewer implements OnInit, OnDestroy, AfterViewChecked {
|
||||
|
||||
nodeId: string;
|
||||
|
||||
private sub: Subscription;
|
||||
|
||||
constructor(private formService: FormService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.sub = this.route.params.subscribe(params => {
|
||||
this.nodeId = params['id'];
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
// workaround for MDL issues with dynamic components
|
||||
if (componentHandler) {
|
||||
componentHandler.upgradeAllRegistered();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
[showUploadDialog]="true"
|
||||
[currentFolderPath]="currentPath"
|
||||
[uploaddirectory]=""
|
||||
[versioning] = "versioning"
|
||||
(onSuccess)="documentList.reload()">
|
||||
<alfresco-document-list-breadcrumb
|
||||
[currentFolderPath]="currentPath"
|
||||
@ -91,7 +92,7 @@
|
||||
handler="delete">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
target="folder"
|
||||
title="Activiti: View Form"
|
||||
(execute)="viewActivitiForm($event)">
|
||||
</content-action>
|
||||
@ -147,6 +148,13 @@
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p style="width:250px;margin: 20px;">
|
||||
<label for="switch-versioning" class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
<input type="checkbox" id="switch-versioning" class="mdl-switch__input" (change)="toggleVersioning()">
|
||||
<span class="mdl-switch__label">Versioning</span>
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<h5>Upload</h5>
|
||||
<br>
|
||||
<div *ngIf="acceptedFilesTypeShow">
|
||||
@ -160,6 +168,7 @@
|
||||
[currentFolderPath]="currentPath"
|
||||
[multipleFiles]="multipleFileUpload"
|
||||
[uploadFolders]="folderUpload"
|
||||
[versioning] = "versioning"
|
||||
(onSuccess)="documentList.reload()">
|
||||
<div class="mdl-spinner mdl-js-spinner is-active"></div>
|
||||
</alfresco-upload-button>
|
||||
@ -171,6 +180,7 @@
|
||||
acceptedFilesType="{{acceptedFilesType}}"
|
||||
[multipleFiles]="multipleFileUpload"
|
||||
[uploadFolders]="folderUpload"
|
||||
[versioning] = "versioning"
|
||||
(onSuccess)="documentList.reload()">
|
||||
<div class="mdl-spinner mdl-js-spinner is-active"></div>
|
||||
</alfresco-upload-button>
|
||||
|
@ -63,6 +63,7 @@ export class FilesComponent implements OnInit {
|
||||
multipleFileUpload: boolean = false;
|
||||
folderUpload: boolean = false;
|
||||
acceptedFilesTypeShow: boolean = false;
|
||||
versioning: boolean = false;
|
||||
|
||||
acceptedFilesType: string = '.jpg,.pdf,.js';
|
||||
|
||||
@ -119,6 +120,11 @@ export class FilesComponent implements OnInit {
|
||||
return this.acceptedFilesTypeShow;
|
||||
}
|
||||
|
||||
toggleVersioning() {
|
||||
this.versioning = !this.versioning;
|
||||
return this.versioning;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.formService.getProcessDefinitions().subscribe(
|
||||
defs => this.setupBpmActions(defs || []),
|
||||
@ -127,7 +133,7 @@ export class FilesComponent implements OnInit {
|
||||
}
|
||||
|
||||
viewActivitiForm(event?: any) {
|
||||
this.router.navigate(['/activiti/tasks', '1']);
|
||||
this.router.navigate(['/activiti/tasksnode', event.value.entry.id]);
|
||||
}
|
||||
|
||||
private setupBpmActions(actions: any[]) {
|
||||
|
@ -16,13 +16,9 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Output } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ALFRESCO_SEARCH_DIRECTIVES } from 'ng2-alfresco-search';
|
||||
import { VIEWERCOMPONENT } from 'ng2-alfresco-viewer';
|
||||
import {
|
||||
AlfrescoAuthenticationService,
|
||||
AlfrescoContentService
|
||||
} from 'ng2-alfresco-core';
|
||||
import { AlfrescoAuthenticationService } from 'ng2-alfresco-core';
|
||||
|
||||
declare let __moduleName: string;
|
||||
|
||||
@ -30,52 +26,36 @@ declare let __moduleName: string;
|
||||
moduleId: __moduleName,
|
||||
selector: 'search-bar',
|
||||
templateUrl: './search-bar.component.html',
|
||||
styles: [`
|
||||
`],
|
||||
directives: [ALFRESCO_SEARCH_DIRECTIVES, VIEWERCOMPONENT]
|
||||
})
|
||||
export class SearchBarComponent {
|
||||
|
||||
urlFile: string;
|
||||
fileName: string;
|
||||
mimeType: string;
|
||||
fileNodeId: string;
|
||||
fileShowed: boolean = false;
|
||||
searchTerm: string = '';
|
||||
|
||||
@Output()
|
||||
expand = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
public router: Router,
|
||||
public auth: AlfrescoAuthenticationService,
|
||||
public contentService: AlfrescoContentService
|
||||
|
||||
) {
|
||||
constructor(public auth: AlfrescoAuthenticationService) {
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return this.auth.isLoggedIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new search term is submitted
|
||||
*
|
||||
* @param params Parameters relating to the search
|
||||
*/
|
||||
searchTermChange(params) {
|
||||
this.router.navigate(['Search', {
|
||||
q: params.value
|
||||
}]);
|
||||
}
|
||||
|
||||
onFileClicked(event) {
|
||||
if (event.value.entry.isFile) {
|
||||
this.fileName = event.value.entry.name;
|
||||
this.mimeType = event.value.entry.content.mimeType;
|
||||
this.urlFile = this.contentService.getContentUrl(event.value);
|
||||
this.fileNodeId = event.value.entry.id;
|
||||
this.fileShowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
searchTermChange(event) {
|
||||
console.log('Search term changed', event);
|
||||
this.searchTerm = event.value;
|
||||
}
|
||||
|
||||
onExpandToggle(event) {
|
||||
this.expand.emit(event);
|
||||
}
|
||||
|
@ -3,6 +3,6 @@
|
||||
<alfresco-search (preview)="onFileClicked($event)"></alfresco-search>
|
||||
</div>
|
||||
|
||||
<alfresco-viewer [(showViewer)]="previewActive" [urlFile]="previewContentUrl" [fileName]="previewName" [mimeType]="previewMimeType" [overlayMode]="true">
|
||||
<alfresco-viewer [(showViewer)]="fileShowed" [fileNodeId]="fileNodeId" [overlayMode]="true">
|
||||
<div class="mdl-spinner mdl-js-spinner is-active"></div>
|
||||
</alfresco-viewer>
|
||||
|
@ -52,10 +52,7 @@ declare let __moduleName: string;
|
||||
})
|
||||
export class SearchComponent {
|
||||
|
||||
previewContentUrl: string;
|
||||
previewName: string;
|
||||
previewMimeType: string;
|
||||
previewActive: boolean = false;
|
||||
fileShowed: boolean = false;
|
||||
fileNodeId: string;
|
||||
|
||||
constructor(public contentService: AlfrescoContentService) {
|
||||
@ -64,7 +61,7 @@ export class SearchComponent {
|
||||
onFileClicked(event) {
|
||||
if (event.value.entry.isFile) {
|
||||
this.fileNodeId = event.value.entry.id;
|
||||
this.previewActive = true;
|
||||
this.fileShowed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ import { bootstrap } from '@angular/platform-browser-dynamic';
|
||||
import { HTTP_PROVIDERS } from '@angular/http';
|
||||
import { ALFRESCO_SEARCH_PROVIDERS } from 'ng2-alfresco-search';
|
||||
import { ALFRESCO_CORE_PROVIDERS } from 'ng2-alfresco-core';
|
||||
import { ATIVITI_FORM_PROVIDERS } from 'ng2-activiti-form';
|
||||
import { UploadService } from 'ng2-alfresco-upload';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
import { appRouterProviders } from './app.routes';
|
||||
|
||||
bootstrap(AppComponent, [
|
||||
@ -29,5 +29,6 @@ bootstrap(AppComponent, [
|
||||
HTTP_PROVIDERS,
|
||||
ALFRESCO_CORE_PROVIDERS,
|
||||
ALFRESCO_SEARCH_PROVIDERS,
|
||||
UploadService
|
||||
UploadService,
|
||||
ATIVITI_FORM_PROVIDERS
|
||||
]).catch(err => console.error(err));
|
||||
|
@ -4,7 +4,7 @@
|
||||
"DOCUMENT_LIST": {
|
||||
"COLUMNS": {
|
||||
"DISPLAY_NAME": "Display name",
|
||||
"CREATED_BY": "mario",
|
||||
"CREATED_BY": "Created by",
|
||||
"CREATED_ON": "Created on"
|
||||
},
|
||||
"ACTIONS": {
|
||||
|
@ -16,6 +16,10 @@
|
||||
<link href="node_modules/flag-icon-css/css/flag-icon.min.css" rel="stylesheet">
|
||||
|
||||
<!-- 1. Load libraries -->
|
||||
<!-- Polyfill(s) for Safari (pre-10.x) -->
|
||||
<script src="node_modules/intl/dist/Intl.min.js"></script>
|
||||
<script src="node_modules/intl/locale-data/jsonp/en.js"></script>
|
||||
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Alfresco-Angular2-Demo",
|
||||
"description": "Demo shell for Alfresco Angular2 components",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
@ -73,18 +73,20 @@
|
||||
"material-design-icons": "2.2.3",
|
||||
"material-design-lite": "1.1.3",
|
||||
"ng2-translate": "2.2.0",
|
||||
"pdfjs-dist": "1.5.258",
|
||||
"pdfjs-dist": "1.5.404",
|
||||
"flag-icon-css": "2.3.0",
|
||||
"ng2-alfresco-core": "0.2.0",
|
||||
"ng2-alfresco-datatable": "0.2.0",
|
||||
"ng2-alfresco-documentlist": "0.2.0",
|
||||
"ng2-alfresco-login": "0.2.0",
|
||||
"ng2-alfresco-search": "0.2.0",
|
||||
"ng2-alfresco-upload": "0.2.0",
|
||||
"ng2-alfresco-viewer": "0.2.0",
|
||||
"ng2-activiti-form": "0.2.0",
|
||||
"ng2-activiti-tasklist": "0.2.0",
|
||||
"ng2-alfresco-webscript": "0.2.0"
|
||||
"intl": "1.2.4",
|
||||
"ng2-alfresco-core": "0.3.0",
|
||||
"ng2-alfresco-datatable": "0.3.0",
|
||||
"ng2-alfresco-documentlist": "0.3.0",
|
||||
"ng2-alfresco-login": "0.3.0",
|
||||
"ng2-alfresco-search": "0.3.0",
|
||||
"ng2-alfresco-upload": "0.3.0",
|
||||
"ng2-alfresco-viewer": "0.3.0",
|
||||
"ng2-activiti-form": "0.3.0",
|
||||
"ng2-activiti-tasklist": "0.3.0",
|
||||
"ng2-activiti-processlist": "0.3.0",
|
||||
"ng2-alfresco-webscript": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "2.0.0",
|
||||
|
@ -22,6 +22,7 @@
|
||||
'ng2-alfresco-webscript': 'node_modules/ng2-alfresco-webscript/dist',
|
||||
'ng2-activiti-tasklist': 'node_modules/ng2-activiti-tasklist/dist',
|
||||
'alfresco-js-api': 'node_modules/alfresco-js-api/dist'
|
||||
'ng2-activiti-processlist': 'node_modules/ng2-activiti-processlist/dist'
|
||||
};
|
||||
// packages tells the System loader how to load when no filename and/or no extension
|
||||
var packages = {
|
||||
@ -39,6 +40,7 @@
|
||||
'ng2-alfresco-upload': { main: 'index.js', defaultExtension: 'js'},
|
||||
'ng2-alfresco-viewer': { main: 'index.js', defaultExtension: 'js'},
|
||||
'ng2-activiti-form': { main: 'index.js', defaultExtension: 'js'},
|
||||
'ng2-activiti-processlist': { main: 'index.js', defaultExtension: 'js'},
|
||||
'ng2-activiti-tasklist': { main: 'index.js', defaultExtension: 'js'},
|
||||
'ng2-alfresco-webscript': { main: 'index.js', defaultExtension: 'js'},
|
||||
'alfresco-js-api': { main: 'alfresco-js-api.js', defaultExtension: 'js'}
|
||||
|
@ -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,14 @@ 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:
|
||||
@ -120,7 +159,7 @@ All `form*` events receive an instance of the `FormModel` as event argument for
|
||||
```html
|
||||
<activiti-form
|
||||
[taskId]="selectedTask?.id"
|
||||
formSaved="onFormSaved($event)">
|
||||
(formSaved)="onFormSaved($event)">
|
||||
</activiti-form>
|
||||
```
|
||||
|
||||
|
@ -15,6 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FormService } from './src/services/form.service';
|
||||
import { EcmModelService } from './src/services/ecm-model.service';
|
||||
import { NodeService } from './src/services/node.service';
|
||||
|
||||
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';
|
||||
|
||||
|
||||
export const ATIVITI_FORM_PROVIDERS: [any] = [
|
||||
FormService,
|
||||
EcmModelService,
|
||||
NodeService
|
||||
];
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ng2-activiti-form",
|
||||
"description": "Alfresco Activiti Form Component for Angular 2",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
@ -65,7 +65,7 @@
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "0.6.12",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0"
|
||||
"ng2-alfresco-core": "0.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"material-design-icons": "^2.2.3",
|
||||
|
@ -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">
|
||||
|
@ -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,8 +180,12 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.nodeId) {
|
||||
this.loadActivitiFormForEcmNode();
|
||||
} else {
|
||||
this.loadForm();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.setupMaterialComponents();
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,9 @@
|
||||
<div *ngSwitchCase="'readonly-text'">
|
||||
<display-text-widget [field]="field" (fieldChanged)="fieldChanged($event);"></display-text-widget>
|
||||
</div>
|
||||
<div *ngSwitchCase="'upload'">
|
||||
<upload-widget [field]="field" (fieldChanged)="fieldChanged($event);"></upload-widget>
|
||||
</div>
|
||||
<div *ngSwitchDefault>
|
||||
<span>UNKNOWN WIDGET TYPE: {{field.type}}</span>
|
||||
</div>
|
||||
|
@ -23,6 +23,7 @@ export class FormFieldTypes {
|
||||
static RADIO_BUTTONS: string = 'radio-buttons';
|
||||
static DISPLAY_VALUE: string = 'readonly';
|
||||
static READONLY_TEXT: string = 'readonly-text';
|
||||
static UPLOAD: string = 'upload';
|
||||
|
||||
static READONLY_TYPES: string[] = [
|
||||
FormFieldTypes.HYPERLINK,
|
||||
|
@ -129,7 +129,9 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
}
|
||||
|
||||
updateForm() {
|
||||
if (this.type === FormFieldTypes.DROPDOWN) {
|
||||
|
||||
switch (this.type) {
|
||||
case FormFieldTypes.DROPDOWN:
|
||||
/*
|
||||
This is needed due to Activiti reading dropdown values as string
|
||||
but saving back as object: { id: <id>, name: <name> }
|
||||
@ -142,7 +144,8 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.form.values[this.id] = entry[0];
|
||||
}
|
||||
}
|
||||
} else if (this.type === FormFieldTypes.RADIO_BUTTONS) {
|
||||
break;
|
||||
case FormFieldTypes.RADIO_BUTTONS:
|
||||
/*
|
||||
This is needed due to Activiti issue related to reading radio button values as value string
|
||||
but saving back as object: { id: <id>, name: <name> }
|
||||
@ -153,7 +156,15 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
} else if (this.options.length > 0) {
|
||||
this.form.values[this.id] = this.options[0];
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.UPLOAD:
|
||||
if (this.value && this.value.length > 0) {
|
||||
this.form.values[this.id] = `${this.value[0].id}`;
|
||||
} else {
|
||||
this.form.values[this.id] = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!FormFieldTypes.isReadOnlyType(this.type)) {
|
||||
this.form.values[this.id] = this.value;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
<div class="dropdown-widget">
|
||||
<label [attr.for]="field.id">{{field.name}}</label>
|
||||
<select [(ngModel)]="field.value" (ngModelChange)="checkVisibility(field)">
|
||||
<option *ngFor="let opt of field.options" [value]="opt.id">{{opt.name}}</option>
|
||||
</select>
|
||||
|
@ -27,6 +27,7 @@ import { HyperlinkWidget } from './hyperlink/hyperlink.widget';
|
||||
import { RadioButtonsWidget } from './radio-buttons/radio-buttons.widget';
|
||||
import { DisplayValueWidget } from './display-value/display-value.widget';
|
||||
import { DisplayTextWidget } from './display-text/display-text.widget';
|
||||
import { UploadWidget } from './upload/upload.widget';
|
||||
|
||||
// core
|
||||
export * from './widget.component';
|
||||
@ -46,6 +47,7 @@ export * from './hyperlink/hyperlink.widget';
|
||||
export * from './radio-buttons/radio-buttons.widget';
|
||||
export * from './display-value/display-value.widget';
|
||||
export * from './display-text/display-text.widget';
|
||||
export * from './upload/upload.widget';
|
||||
|
||||
export const CONTAINER_WIDGET_DIRECTIVES: [any] = [
|
||||
TabsWidget,
|
||||
@ -61,7 +63,8 @@ export const PRIMITIVE_WIDGET_DIRECTIVES: [any] = [
|
||||
HyperlinkWidget,
|
||||
RadioButtonsWidget,
|
||||
DisplayValueWidget,
|
||||
DisplayTextWidget
|
||||
DisplayTextWidget,
|
||||
UploadWidget
|
||||
];
|
||||
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
.upload-widget {
|
||||
width:100%
|
||||
}
|
||||
|
||||
.upload-widget__icon {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.upload-widget__file {
|
||||
float: left;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.upload-widget__reset {
|
||||
float: left;
|
||||
margin-top: 4px;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<div class="upload-widget">
|
||||
|
||||
<label [attr.for]="field.id">{{field.name}}</label>
|
||||
<div>
|
||||
<i class="material-icons upload-widget__icon">image</i>
|
||||
<span *ngIf="hasFile" class="upload-widget__file">{{getUploadedFileName()}}</span>
|
||||
<input *ngIf="!hasFile"
|
||||
#file
|
||||
type="file"
|
||||
[attr.id]="field.id"
|
||||
class="upload-widget__file"
|
||||
(change)="onFileChanged($event)">
|
||||
<button *ngIf="hasFile" (click)="reset(file);" class="upload-widget__reset">X</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,105 @@
|
||||
/*!
|
||||
* @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 } from '@angular/core';
|
||||
import { WidgetComponent } from './../widget.component';
|
||||
import { AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
|
||||
|
||||
declare let __moduleName: string;
|
||||
declare var componentHandler;
|
||||
|
||||
@Component({
|
||||
moduleId: __moduleName,
|
||||
selector: 'upload-widget',
|
||||
templateUrl: './upload.widget.html',
|
||||
styleUrls: ['./upload.widget.css']
|
||||
})
|
||||
export class UploadWidget extends WidgetComponent implements OnInit {
|
||||
|
||||
constructor(private settingsService: AlfrescoSettingsService,
|
||||
private authService: AlfrescoAuthenticationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
hasFile: boolean;
|
||||
fileName: string;
|
||||
|
||||
ngOnInit() {
|
||||
if (this.field &&
|
||||
this.field.value &&
|
||||
this.field.value.length > 0) {
|
||||
this.hasFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
getUploadedFileName(): string {
|
||||
let result = this.fileName;
|
||||
|
||||
if (this.field &&
|
||||
this.field.value &&
|
||||
this.field.value.length > 0) {
|
||||
let file = this.field.value[0];
|
||||
result = file.name;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.field.value = null;
|
||||
this.field.json.value = null;
|
||||
this.hasFile = false;
|
||||
}
|
||||
|
||||
onFileChanged(event: any) {
|
||||
let files = event.srcElement.files;
|
||||
if (files && files.length > 0) {
|
||||
|
||||
let file = files[0];
|
||||
|
||||
this.hasFile = true;
|
||||
this.fileName = file.name;
|
||||
|
||||
let formData: FormData = new FormData();
|
||||
formData.append('file', file, file.name);
|
||||
|
||||
let xhr: XMLHttpRequest = new XMLHttpRequest();
|
||||
|
||||
xhr.withCredentials = true;
|
||||
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
let jsonFile = JSON.parse(xhr.response);
|
||||
console.log(jsonFile);
|
||||
this.field.value = [jsonFile];
|
||||
this.field.json.value = [jsonFile];
|
||||
} else {
|
||||
console.error(xhr.response);
|
||||
window.alert('Error uploading file. See console output for more details.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let url = `${this.settingsService.bpmHost}/activiti-app/app/rest/content/raw`;
|
||||
xhr.open('POST', url, true);
|
||||
xhr.setRequestHeader('Authorization', this.authService.getTicketBpm());
|
||||
xhr.send(formData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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.searchEcmType(formName, EcmModelService.MODEL_NAME).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 searchEcmType(typeName: string, modelName: string): Observable<any> {
|
||||
return this.getEcmType(modelName).map(function (customTypes: any) {
|
||||
return customTypes.list.entries.find(type => type.entry.prefixedName === typeName || type.entry.title === typeName);
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
];
|
||||
});
|
||||
|
||||
|
@ -19,6 +19,8 @@ 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.searchEcmType(formName, EcmModelService.MODEL_NAME).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);
|
||||
}
|
||||
}
|
@ -236,6 +236,7 @@ describe('WidgetVisibilityService', () => {
|
||||
expect(varValue).toBe('form_value_test');
|
||||
});
|
||||
|
||||
/*
|
||||
it('should return null if the variable does not exist', (done) => {
|
||||
service.getTaskProcessVariableModelsForTask(9999).subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
@ -252,6 +253,7 @@ describe('WidgetVisibilityService', () => {
|
||||
|
||||
expect(varValue).toBe(null);
|
||||
});
|
||||
*/
|
||||
|
||||
it('should be able to retrieve a field value searching in the form', () => {
|
||||
let stubFormWithFields = new FormModel(fakeFormJson);
|
||||
@ -360,6 +362,7 @@ describe('WidgetVisibilityService', () => {
|
||||
expect(rightValue).toBe(null);
|
||||
});
|
||||
|
||||
/*
|
||||
it('should retrieve the value for the left field when it is a process variable', (variableUpdated) => {
|
||||
service.getTaskProcessVariableModelsForTask(9999).subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
@ -379,6 +382,7 @@ describe('WidgetVisibilityService', () => {
|
||||
expect(rightValue).not.toBe(null);
|
||||
expect(rightValue).toBe('test_value_2');
|
||||
});
|
||||
*/
|
||||
|
||||
it('should retrieve the value for the left field when it is a form variable', () => {
|
||||
let fakeForm = new FormModel({variables: [
|
||||
@ -484,6 +488,7 @@ describe('WidgetVisibilityService', () => {
|
||||
expect(isVisible).toBeTruthy();
|
||||
});
|
||||
|
||||
/*
|
||||
it('should evaluate visibility with multiple conditions', (ready) => {
|
||||
service.getTaskProcessVariableModelsForTask(9999).subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
@ -510,6 +515,7 @@ describe('WidgetVisibilityService', () => {
|
||||
|
||||
expect(isVisible).toBeTruthy();
|
||||
});
|
||||
*/
|
||||
|
||||
it('should return true when the visibility condition is not valid', () => {
|
||||
let visibilityObjTest = new WidgetVisibilityModel();
|
||||
|
@ -10,4 +10,6 @@ src/**/*.d.ts
|
||||
demo/**/*.js
|
||||
demo/**/*.js.map
|
||||
demo/**/*.d.ts
|
||||
index.js
|
||||
index.js.map
|
||||
!systemjs.config.js
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*!
|
||||
* @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 { DatePipe } from '@angular/common';
|
||||
import {
|
||||
DataTableAdapter, ObjectDataTableAdapter, ObjectDataColumn,
|
||||
DataRow, DataColumn, DataSorting
|
||||
} from 'ng2-alfresco-datatable';
|
||||
|
||||
export class ProcessListDataTableAdapter extends ObjectDataTableAdapter implements DataTableAdapter {
|
||||
|
||||
ERR_ROW_NOT_FOUND: string = 'Row not found';
|
||||
ERR_COL_NOT_FOUND: string = 'Column not found';
|
||||
|
||||
DEFAULT_DATE_FORMAT: string = 'medium';
|
||||
|
||||
private sorting: DataSorting;
|
||||
private rows: DataRow[];
|
||||
private columns: DataColumn[];
|
||||
|
||||
constructor(rows: any, schema: DataColumn[]) {
|
||||
super(rows, schema);
|
||||
this.rows = rows;
|
||||
this.columns = schema || [];
|
||||
}
|
||||
|
||||
getRows(): Array<DataRow> {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
// TODO: disable this api
|
||||
setRows(rows: Array<DataRow>) {
|
||||
this.rows = rows || [];
|
||||
this.sort();
|
||||
}
|
||||
|
||||
getColumns(): Array<DataColumn> {
|
||||
return this.columns;
|
||||
}
|
||||
|
||||
setColumns(columns: Array<DataColumn>) {
|
||||
this.columns = columns || [];
|
||||
}
|
||||
|
||||
getValue(row: DataRow, col: DataColumn): any {
|
||||
if (!row) {
|
||||
throw new Error(this.ERR_ROW_NOT_FOUND);
|
||||
}
|
||||
if (!col) {
|
||||
throw new Error(this.ERR_COL_NOT_FOUND);
|
||||
}
|
||||
let value = row.getValue(col.key);
|
||||
|
||||
if (col.type === 'date') {
|
||||
let datePipe = new DatePipe();
|
||||
let format = (<ActivitiDataColumn>(col)).format || this.DEFAULT_DATE_FORMAT;
|
||||
try {
|
||||
return datePipe.transform(value, format);
|
||||
} catch (err) {
|
||||
console.error(`Error parsing date ${value} to format ${format}`);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
getSorting(): DataSorting {
|
||||
return this.sorting;
|
||||
}
|
||||
|
||||
setSorting(sorting: DataSorting): void {
|
||||
this.sorting = sorting;
|
||||
|
||||
if (sorting && sorting.key && this.rows && this.rows.length > 0) {
|
||||
this.rows.sort((a: DataRow, b: DataRow) => {
|
||||
let left = a.getValue(sorting.key);
|
||||
if (left) {
|
||||
left = (left instanceof Date) ? left.valueOf().toString() : left.toString();
|
||||
} else {
|
||||
left = '';
|
||||
}
|
||||
|
||||
let right = b.getValue(sorting.key);
|
||||
if (right) {
|
||||
right = (right instanceof Date) ? right.valueOf().toString() : right.toString();
|
||||
} else {
|
||||
right = '';
|
||||
}
|
||||
|
||||
return sorting.direction === 'asc'
|
||||
? left.localeCompare(right)
|
||||
: right.localeCompare(left);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sort(key?: string, direction?: string): void {
|
||||
let sorting = this.sorting || new DataSorting();
|
||||
if (key) {
|
||||
sorting.key = key;
|
||||
sorting.direction = direction || 'asc';
|
||||
}
|
||||
this.setSorting(sorting);
|
||||
}
|
||||
}
|
||||
|
||||
export class ActivitiDataColumn extends ObjectDataColumn {
|
||||
format: string;
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
"reflect-metadata": "^0.1.3",
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "^0.6.12",
|
||||
"ng2-activiti-processlist": "file:../",
|
||||
"ng2-activiti-processlist": "^0.3.0",
|
||||
"material-design-icons": "^2.2.3",
|
||||
"material-design-lite": "^1.1.3"
|
||||
},
|
||||
|
@ -44,7 +44,7 @@ import {
|
||||
<label for="token"><b>Insert a servicePath</b></label><br>
|
||||
<input id="token" type="text" size="48" [(ngModel)]="servicePath"><br>
|
||||
<div class="container" *ngIf="authenticated">
|
||||
<activiti-processlist></activiti-processlist>
|
||||
<activiti-process-instance-list></activiti-process-instance-list>
|
||||
</div>`,
|
||||
providers: [ACTIVITI_PROCESSLIST_PROVIDERS],
|
||||
directives: [ACTIVITI_PROCESSLIST_DIRECTIVES]
|
||||
|
@ -15,17 +15,30 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ActivitiProcesslistComponent } from './src/components/activiti-processlist.component';
|
||||
import { ActivitiProcessInstanceListComponent } from './src/components/activiti-processlist.component';
|
||||
import { ActivitiProcessFilters } from './src/components/activiti-filters.component';
|
||||
import { ActivitiProcessInstanceHeader } from './src/components/activiti-process-instance-header.component';
|
||||
import { ActivitiProcessInstanceTasks } from './src/components/activiti-process-instance-tasks.component';
|
||||
import { ActivitiComments } from './src/components/activiti-comments.component';
|
||||
import { ActivitiProcessInstanceDetails } from './src/components/activiti-process-instance-details.component';
|
||||
import { ActivitiStartProcessButton } from './src/components/activiti-start-process.component';
|
||||
import { ActivitiProcessService } from './src/services/activiti-process.service';
|
||||
|
||||
// components
|
||||
export * from './src/components/activiti-processlist.component';
|
||||
export * from './src/components/activiti-process-instance-details.component';
|
||||
|
||||
// services
|
||||
export * from './src/services/activiti-process.service';
|
||||
|
||||
export const ACTIVITI_PROCESSLIST_DIRECTIVES: [any] = [
|
||||
ActivitiProcesslistComponent
|
||||
ActivitiProcessInstanceListComponent,
|
||||
ActivitiProcessFilters,
|
||||
ActivitiProcessInstanceDetails,
|
||||
ActivitiProcessInstanceHeader,
|
||||
ActivitiProcessInstanceTasks,
|
||||
ActivitiComments,
|
||||
ActivitiStartProcessButton
|
||||
];
|
||||
|
||||
export const ACTIVITI_PROCESSLIST_PROVIDERS: [any] = [
|
||||
|
@ -20,6 +20,9 @@ module.exports = function (config) {
|
||||
{pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.js', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.html', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.css', 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/**/*.html', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-activiti-tasklist/dist/**/*.css', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', included: true, watched: false},
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ng2-activiti-processlist",
|
||||
"description": "Show active processes from the Activiti BPM suite",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
@ -63,8 +63,9 @@
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "^0.6.12",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0",
|
||||
"ng2-alfresco-datatable": "0.2.0"
|
||||
"ng2-alfresco-core": "0.3.0",
|
||||
"ng2-alfresco-datatable": "0.3.0",
|
||||
"ng2-activiti-tasklist": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-cli": "1.0.0-beta.9",
|
||||
|
@ -0,0 +1,7 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<span class="activiti-label mdl-badge"
|
||||
[attr.data-badge]="comments?.length">{{ 'DETAILS.LABELS.COMMENTS' |translate }}</span>
|
||||
<div id="addComment" (click)="showDialog()" class="icon material-icons">add</div>
|
||||
<div class="mdl-tooltip" for="addComment">
|
||||
Add a comment
|
||||
</div>
|
||||
|
||||
<div class="menu-container" *ngIf="comments?.length > 0">
|
||||
<ul class='mdl-list'>
|
||||
<li class="mdl-list__item" *ngFor="let comment of comments">
|
||||
<span class="mdl-list__item-primary-content">
|
||||
<i class="material-icons mdl-list__item-icon">comment</i>
|
||||
{{comment.message}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="comments?.length === 0">
|
||||
{{ 'DETAILS.COMMENTS.NONE' | translate }}
|
||||
</div>
|
||||
|
||||
|
||||
<dialog class="mdl-dialog" #dialog>
|
||||
<h4 class="mdl-dialog__title">New comment</h4>
|
||||
<div class="mdl-dialog__content">
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||
<textarea class="mdl-textfield__input" type="text" [(ngModel)]="message" rows="1" id="commentText"></textarea>
|
||||
<label class="mdl-textfield__label" for="commentText">Message</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdl-dialog__actions">
|
||||
<button type="button" (click)="add()" class="mdl-button">Add Comment</button>
|
||||
<button type="button" (click)="cancel()" class="mdl-button close">Cancel</button>
|
||||
</div>
|
||||
</dialog>
|
@ -0,0 +1,121 @@
|
||||
/*!
|
||||
* @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, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { Comment } from '../models/comment.model';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-comments',
|
||||
moduleId: __moduleName,
|
||||
templateUrl: './activiti-comments.component.html',
|
||||
styleUrls: ['./activiti-comments.component.css'],
|
||||
providers: [ActivitiProcessService],
|
||||
pipes: [ AlfrescoPipeTranslate ]
|
||||
|
||||
})
|
||||
export class ActivitiComments implements OnInit {
|
||||
|
||||
@Input()
|
||||
processId: string;
|
||||
|
||||
@ViewChild('dialog')
|
||||
dialog: any;
|
||||
|
||||
comments: Comment [] = [];
|
||||
|
||||
private commentObserver: Observer<Comment>;
|
||||
comment$: Observable<Comment>;
|
||||
|
||||
message: string;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src');
|
||||
}
|
||||
|
||||
this.comment$ = new Observable<Comment>(observer => this.commentObserver = observer).share();
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.comment$.subscribe((comment: Comment) => {
|
||||
this.comments.push(comment);
|
||||
});
|
||||
|
||||
if (this.processId) {
|
||||
this.load(this.processId);
|
||||
}
|
||||
}
|
||||
|
||||
public load(taskId: string) {
|
||||
this.comments = [];
|
||||
if (this.processId) {
|
||||
this.activitiProcess.getProcessInstanceComments(this.processId).subscribe(
|
||||
(res: Comment[]) => {
|
||||
res.forEach((comment) => {
|
||||
this.commentObserver.next(comment);
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.comments = [];
|
||||
}
|
||||
}
|
||||
|
||||
public showDialog() {
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.showModal();
|
||||
}
|
||||
}
|
||||
|
||||
public add() {
|
||||
this.activitiProcess.addProcessInstanceComment(this.processId, this.message).subscribe(
|
||||
(res: Comment) => {
|
||||
this.comments.push(res);
|
||||
this.message = '';
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
.mdl-list__item {
|
||||
cursor: pointer;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<div class="menu-container">
|
||||
<ul class='mdl-list'>
|
||||
<li class="mdl-list__item"(click)="selectFilter(filter)" *ngFor="let filter of filters">
|
||||
<span class="mdl-list__item-primary-content">
|
||||
<i class="material-icons mdl-list__item-icon">assignment</i>
|
||||
{{filter.name}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
@ -0,0 +1,131 @@
|
||||
/*!
|
||||
* @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, Output, EventEmitter, OnInit, Input } from '@angular/core';
|
||||
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { FilterModel } from '../models/filter.model';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-process-filters',
|
||||
moduleId: __moduleName,
|
||||
templateUrl: './activiti-filters.component.html',
|
||||
styleUrls: ['activiti-filters.component.css'],
|
||||
providers: [ActivitiProcessService],
|
||||
pipes: [AlfrescoPipeTranslate]
|
||||
|
||||
})
|
||||
export class ActivitiProcessFilters implements OnInit {
|
||||
|
||||
@Output()
|
||||
filterClick: EventEmitter<FilterModel> = new EventEmitter<FilterModel>();
|
||||
|
||||
@Output()
|
||||
onSuccess: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
onError: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Input()
|
||||
appId: string;
|
||||
|
||||
@Input()
|
||||
appName: string;
|
||||
|
||||
private filterObserver: Observer<FilterModel>;
|
||||
filter$: Observable<FilterModel>;
|
||||
|
||||
currentFilter: FilterModel;
|
||||
|
||||
filters: FilterModel [] = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param activiti
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
public activiti: ActivitiProcessService) {
|
||||
this.filter$ = new Observable<FilterModel>(observer => this.filterObserver = observer).share();
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.filter$.subscribe((filter: FilterModel) => {
|
||||
this.filters.push(filter);
|
||||
});
|
||||
|
||||
this.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* The method call the adapter data table component for render the task list
|
||||
* @param tasks
|
||||
*/
|
||||
private load() {
|
||||
if (this.appName) {
|
||||
this.filterByAppName();
|
||||
} else {
|
||||
this.filterByAppId(this.appId);
|
||||
}
|
||||
}
|
||||
|
||||
private filterByAppId(appId) {
|
||||
this.activiti.getProcessFilters(appId).subscribe(
|
||||
(res: FilterModel[]) => {
|
||||
res.forEach((filter) => {
|
||||
this.filterObserver.next(filter);
|
||||
});
|
||||
this.onSuccess.emit(res);
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
this.onError.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private filterByAppName() {
|
||||
this.activiti.getDeployedApplications(this.appName).subscribe(
|
||||
application => {
|
||||
this.filterByAppId(application.id);
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
this.onError.emit(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the selected filter as next
|
||||
* @param filter
|
||||
*/
|
||||
public selectFilter(filter: FilterModel) {
|
||||
this.currentFilter = filter;
|
||||
this.filterClick.emit(filter);
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<div *ngIf="!processInstanceDetails">{{ 'DETAILS.MESSAGES.NONE'|translate }}</div>
|
||||
<div *ngIf="processInstanceDetails">
|
||||
<h2 class="mdl-card__title-text">{{processInstanceDetails.name}}</h2>
|
||||
<activiti-process-instance-header [processInstance]="processInstanceDetails" (processCancelled)="processCancelled()" #activitiprocessheader></activiti-process-instance-header>
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--8-col">
|
||||
<activiti-process-instance-tasks [processId]="processInstanceDetails.id" (taskFormCompleted)="taskFormCompleted()" #activitiprocesstasks></activiti-process-instance-tasks>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<activiti-comments [processId]="processInstanceDetails.id" #activitiprocesscomments></activiti-comments>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,108 @@
|
||||
/*!
|
||||
* @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, Input, ViewChild, Output, EventEmitter } from '@angular/core';
|
||||
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { ActivitiProcessInstanceHeader } from './activiti-process-instance-header.component';
|
||||
import { ActivitiProcessInstanceTasks } from './activiti-process-instance-tasks.component';
|
||||
import { ActivitiComments } from './activiti-comments.component';
|
||||
import { ProcessInstance } from '../models/process-instance';
|
||||
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-process-instance-details',
|
||||
moduleId: __moduleName,
|
||||
templateUrl: './activiti-process-instance-details.component.html',
|
||||
styleUrls: ['./activiti-process-instance-details.component.css'],
|
||||
providers: [ActivitiProcessService],
|
||||
directives: [ActivitiProcessInstanceHeader, ActivitiComments, ActivitiProcessInstanceTasks],
|
||||
pipes: [AlfrescoPipeTranslate]
|
||||
|
||||
})
|
||||
export class ActivitiProcessInstanceDetails {
|
||||
|
||||
@Input()
|
||||
processInstanceId: string;
|
||||
|
||||
@ViewChild('activitiprocessheader')
|
||||
processInstanceHeader: ActivitiProcessInstanceHeader;
|
||||
|
||||
@ViewChild('activitiprocesstasks')
|
||||
tasksList: ActivitiProcessInstanceTasks;
|
||||
|
||||
@ViewChild('activitiprocesscomments')
|
||||
commentsList: ActivitiComments;
|
||||
|
||||
@Input()
|
||||
showTitle: boolean = true;
|
||||
|
||||
@Input()
|
||||
showRefreshButton: boolean = true;
|
||||
|
||||
@Output()
|
||||
processCancelledEmitter = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
taskFormCompletedEmitter = new EventEmitter();
|
||||
|
||||
processInstanceDetails: ProcessInstance;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param activitiProcess
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src');
|
||||
}
|
||||
}
|
||||
|
||||
load(processId: string) {
|
||||
if (processId) {
|
||||
this.activitiProcess.getProcess(processId).subscribe(
|
||||
(res: ProcessInstance) => {
|
||||
this.processInstanceDetails = res;
|
||||
if (this.processInstanceDetails) {
|
||||
if (this.commentsList) {
|
||||
this.commentsList.load(this.processInstanceDetails.id);
|
||||
}
|
||||
if (this.tasksList) {
|
||||
this.tasksList.load(this.processInstanceDetails.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
processCancelled(data: any) {
|
||||
this.processCancelledEmitter.emit(data);
|
||||
}
|
||||
|
||||
taskFormCompleted(data: any) {
|
||||
this.taskFormCompletedEmitter.emit(data);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<div *ngIf="processInstance">
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.STARTED_BY' | translate }}</span>:
|
||||
{{getStartedByFullName()}}
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<span class="activiti-label">{{ 'DETAILS.LABELS.STARTED' | translate }}</span>:
|
||||
{{getStartedDate() | date:'medium'}}
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--4-col">
|
||||
<button type="button" (click)="cancelProcess()" class="mdl-button">{{ 'DETAILS.BUTTON.CANCEL' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* @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, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
|
||||
import { ProcessInstance } from '../models/process-instance';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-process-instance-header',
|
||||
moduleId: __moduleName,
|
||||
templateUrl: './activiti-process-instance-header.component.html',
|
||||
styleUrls: ['./activiti-process-instance-header.component.css'],
|
||||
pipes: [ AlfrescoPipeTranslate ]
|
||||
|
||||
})
|
||||
export class ActivitiProcessInstanceHeader {
|
||||
|
||||
@Input()
|
||||
processInstance: ProcessInstance;
|
||||
|
||||
@Output()
|
||||
processCancelled = new EventEmitter();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param activitiProcess
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
}
|
||||
|
||||
getStartedByFullName() {
|
||||
if (this.processInstance && this.processInstance.startedBy) {
|
||||
return (this.processInstance.startedBy.firstName && this.processInstance.startedBy.firstName !== 'null'
|
||||
? this.processInstance.startedBy.firstName + ' ' : '') +
|
||||
this.processInstance.startedBy.lastName;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
getStartedDate() {
|
||||
return this.processInstance ? new Date(this.processInstance.started) : null;
|
||||
}
|
||||
|
||||
cancelProcess() {
|
||||
this.processCancelled.emit(this.activitiProcess.cancelProcess(this.processInstance.id));
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.material-icons:hover {
|
||||
color: rgb(255, 152, 0);
|
||||
}
|
||||
|
||||
.task-details-dialog {
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.process-tasks-refresh {
|
||||
float: right;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<div *ngIf="showRefreshButton" class="process-tasks-refresh" >
|
||||
<button (click)="onRefreshClicked()"
|
||||
class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
|
||||
<i class="material-icons">refresh</i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="activiti-label mdl-badge"
|
||||
[attr.data-badge]="activeTasks?.length">{{ 'DETAILS.LABELS.TASKS_ACTIVE'|translate }}</span>
|
||||
|
||||
<div class="menu-container" *ngIf="activeTasks?.length > 0">
|
||||
<ul class='mdl-list'>
|
||||
<li class="mdl-list__item mdl-list__item--two-line" *ngFor="let task of activeTasks">
|
||||
<span class="mdl-list__item-primary-content" (click)="clickTask($event, task)">
|
||||
<i class="material-icons mdl-list__item-icon">assignment</i>
|
||||
<span>{{task.name}}</span>
|
||||
<span class="mdl-list__item-sub-title">{{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user: getUserFullName(task.assignee), created: task.created | date:'mediumDate' } }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="activeTasks?.length === 0">
|
||||
{{ 'DETAILS.TASKS.NO_ACTIVE' | translate }}
|
||||
</div>
|
||||
|
||||
<span class="activiti-label mdl-badge"
|
||||
[attr.data-badge]="completedTasks?.length">{{ 'DETAILS.LABELS.TASKS_COMPLETED'|translate }}</span>
|
||||
|
||||
<div class="menu-container" *ngIf="completedTasks?.length > 0">
|
||||
<ul class='mdl-list'>
|
||||
<li class="mdl-list__item mdl-list__item--two-line" *ngFor="let task of completedTasks">
|
||||
<span class="mdl-list__item-primary-content" (click)="clickTask($event, task)">
|
||||
<i class="material-icons mdl-list__item-icon">assignment</i>
|
||||
<span>{{task.name}}</span>
|
||||
<span class="mdl-list__item-sub-title">{{ 'DETAILS.LABELS.TASK_SUBTITLE' | translate:{user: getUserFullName(task.assignee), created: task.created | date:'mediumDate' } }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="completedTasks?.length === 0">
|
||||
{{ 'DETAILS.TASKS.NO_COMPLETED' | translate }}
|
||||
</div>
|
||||
|
||||
<dialog class="mdl-dialog task-details-dialog" #dialog>
|
||||
<h4 class="mdl-dialog__title">{{ 'DETAILS.TASKS.TASK_DETAILS' | translate }}</h4>
|
||||
<div class="mdl-dialog__content">
|
||||
<activiti-task-details [taskId]="selectedTaskId" (formCompleted)="taskFormCompleted()" #taskdetails></activiti-task-details>
|
||||
</div>
|
||||
<div class="mdl-dialog__actions">
|
||||
<button type="button" (click)="cancelDialog()" class="mdl-button close">{{ 'DETAILS.TASKS.TASK_CLOSE' | translate }}</button>
|
||||
</div>
|
||||
</dialog>
|
@ -0,0 +1,182 @@
|
||||
/*!
|
||||
* @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, Input, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
|
||||
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
import { TaskDetailsModel } from '../models/task-details.model';
|
||||
import { ALFRESCO_TASKLIST_DIRECTIVES } from 'ng2-activiti-tasklist';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-process-instance-tasks',
|
||||
moduleId: __moduleName,
|
||||
templateUrl: './activiti-process-instance-tasks.component.html',
|
||||
styleUrls: ['./activiti-process-instance-tasks.component.css'],
|
||||
providers: [ActivitiProcessService],
|
||||
directives: [ ALFRESCO_TASKLIST_DIRECTIVES ],
|
||||
pipes: [ AlfrescoPipeTranslate ]
|
||||
|
||||
})
|
||||
export class ActivitiProcessInstanceTasks implements OnInit {
|
||||
|
||||
@Input()
|
||||
processId: string;
|
||||
|
||||
@Input()
|
||||
showRefreshButton: boolean = true;
|
||||
|
||||
@Output()
|
||||
taskFormCompletedEmitter = new EventEmitter();
|
||||
|
||||
activeTasks: TaskDetailsModel[] = [];
|
||||
completedTasks: TaskDetailsModel[] = [];
|
||||
|
||||
private taskObserver: Observer<TaskDetailsModel>;
|
||||
private completedTaskObserver: Observer<TaskDetailsModel>;
|
||||
|
||||
task$: Observable<TaskDetailsModel>;
|
||||
completedTask$: Observable<TaskDetailsModel>;
|
||||
|
||||
message: string;
|
||||
|
||||
selectedTaskId: string;
|
||||
|
||||
@ViewChild('dialog')
|
||||
dialog: any;
|
||||
|
||||
@ViewChild('taskdetails')
|
||||
taskdetails: any;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param activitiProcess
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src');
|
||||
}
|
||||
|
||||
this.task$ = new Observable<TaskDetailsModel>(observer => this.taskObserver = observer).share();
|
||||
this.completedTask$ = new Observable<TaskDetailsModel>(observer => this.completedTaskObserver = observer).share();
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.task$.subscribe((task: TaskDetailsModel) => {
|
||||
this.activeTasks.push(task);
|
||||
});
|
||||
this.completedTask$.subscribe((task: TaskDetailsModel) => {
|
||||
this.completedTasks.push(task);
|
||||
});
|
||||
|
||||
if (this.processId) {
|
||||
this.load(this.processId);
|
||||
}
|
||||
}
|
||||
|
||||
public load(processId: string) {
|
||||
this.loadActive(processId);
|
||||
this.loadCompleted(processId);
|
||||
}
|
||||
|
||||
public loadActive(processId: string) {
|
||||
this.activeTasks = [];
|
||||
if (processId) {
|
||||
this.activitiProcess.getProcessTasks(processId, null).subscribe(
|
||||
(res: TaskDetailsModel[]) => {
|
||||
res.forEach((task) => {
|
||||
this.taskObserver.next(task);
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.activeTasks = [];
|
||||
}
|
||||
}
|
||||
|
||||
public loadCompleted(processId: string) {
|
||||
this.completedTasks = [];
|
||||
if (processId) {
|
||||
this.activitiProcess.getProcessTasks(processId, 'completed').subscribe(
|
||||
(res: TaskDetailsModel[]) => {
|
||||
res.forEach((task) => {
|
||||
this.completedTaskObserver.next(task);
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.completedTasks = [];
|
||||
}
|
||||
}
|
||||
|
||||
getUserFullName(user: any) {
|
||||
if (user) {
|
||||
return (user.firstName && user.firstName !== 'null'
|
||||
? user.firstName + ' ' : '') +
|
||||
user.lastName;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public clickTask($event: any, task: TaskDetailsModel) {
|
||||
this.selectedTaskId = task.id;
|
||||
this.taskdetails.loadDetails(task.id);
|
||||
this.showDialog();
|
||||
}
|
||||
|
||||
public showDialog() {
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.showModal();
|
||||
}
|
||||
}
|
||||
|
||||
public cancelDialog() {
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
private closeDialog() {
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.close();
|
||||
}
|
||||
}
|
||||
|
||||
public taskFormCompleted() {
|
||||
this.closeDialog();
|
||||
this.load(this.processId);
|
||||
this.taskFormCompletedEmitter.emit(this.processId);
|
||||
}
|
||||
|
||||
public onRefreshClicked() {
|
||||
this.load(this.processId);
|
||||
}
|
||||
}
|
@ -1,6 +1,12 @@
|
||||
<h1>My Activiti Processes</h1>
|
||||
|
||||
<p *ngIf="processInstances && processInstances.length == 0">{{ 'PROCESSLIST.NONE' | translate }}</p>
|
||||
<div *ngIf="!filter">{{ 'FILTERS.MESSAGES.NONE' | translate }}</div>
|
||||
<div *ngIf="filter">
|
||||
<div *ngIf="!isListEmpty()">
|
||||
<alfresco-datatable
|
||||
[data]="data">
|
||||
[data]="data"
|
||||
(rowClick)="onRowClick($event)">
|
||||
</alfresco-datatable>
|
||||
</div>
|
||||
<div *ngIf="isListEmpty()">
|
||||
{{ 'PROCESSLIST.NONE' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,65 +0,0 @@
|
||||
/*!
|
||||
* @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 {describe, expect, it, inject, beforeEachProviders, beforeEach} from '@angular/core/testing';
|
||||
import {TestComponentBuilder} from '@angular/compiler/testing';
|
||||
import {AlfrescoSettingsService, AlfrescoTranslationService, AlfrescoAuthenticationService} from 'ng2-alfresco-core';
|
||||
import {ActivitiProcesslistComponent} from '../../src/components/activiti-processlist.component';
|
||||
import {TranslationMock} from './../assets/translation.service.mock';
|
||||
import {ActivitiProcessService} from '../services/activiti-process.service';
|
||||
|
||||
describe('ActivitiProcesslistComponent', () => {
|
||||
|
||||
let processlistComponentFixture, element, component;
|
||||
|
||||
|
||||
beforeEachProviders(() => {
|
||||
return [
|
||||
ActivitiProcessService,
|
||||
AlfrescoSettingsService,
|
||||
AlfrescoAuthenticationService,
|
||||
{provide: AlfrescoTranslationService, useClass: TranslationMock}
|
||||
];
|
||||
});
|
||||
|
||||
beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
return tcb
|
||||
.createAsync(ActivitiProcesslistComponent)
|
||||
.then(fixture => {
|
||||
processlistComponentFixture = fixture;
|
||||
element = processlistComponentFixture.nativeElement;
|
||||
component = processlistComponentFixture.componentInstance;
|
||||
});
|
||||
}));
|
||||
|
||||
it('should have a valid title', () => {
|
||||
expect(element.querySelector('h1')).toBeDefined();
|
||||
expect(element.getElementsByTagName('h1')[0].innerHTML).toEqual('My Activiti Processes');
|
||||
});
|
||||
|
||||
it('should contain a list of processes', () => {
|
||||
let componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
|
||||
component.ngOnInit();
|
||||
processlistComponentFixture.detectChanges();
|
||||
expect(element.querySelector('table')).toBeDefined();
|
||||
expect(element.querySelectorAll('table tbody tr').length).toEqual(1);
|
||||
});
|
||||
});
|
@ -15,17 +15,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Component, OnInit } from '@angular/core';
|
||||
import {Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { AlfrescoPipeTranslate, AlfrescoTranslationService, CONTEXT_MENU_DIRECTIVES, CONTEXT_MENU_PROVIDERS } from 'ng2-alfresco-core';
|
||||
import { ALFRESCO_DATATABLE_DIRECTIVES, ObjectDataTableAdapter } from 'ng2-alfresco-datatable';
|
||||
import { ALFRESCO_DATATABLE_DIRECTIVES, ObjectDataTableAdapter, DataRowEvent } from 'ng2-alfresco-datatable';
|
||||
import { ActivitiProcessService } from '../services/activiti-process.service';
|
||||
import { ProcessInstance } from '../models/process-instance';
|
||||
import { FilterModel } from '../models/filter.model';
|
||||
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
moduleId: __moduleName,
|
||||
selector: 'activiti-processlist',
|
||||
selector: 'activiti-process-instance-list',
|
||||
styles: [
|
||||
`
|
||||
:host h1 {
|
||||
@ -36,13 +36,33 @@ declare let __moduleName: string;
|
||||
templateUrl: './activiti-processlist.component.html',
|
||||
directives: [ ALFRESCO_DATATABLE_DIRECTIVES, CONTEXT_MENU_DIRECTIVES ],
|
||||
pipes: [ AlfrescoPipeTranslate ],
|
||||
providers: [ CONTEXT_MENU_PROVIDERS ]
|
||||
providers: [ CONTEXT_MENU_PROVIDERS, ActivitiProcessService ]
|
||||
})
|
||||
export class ActivitiProcesslistComponent implements OnInit {
|
||||
export class ActivitiProcessInstanceListComponent implements OnInit {
|
||||
|
||||
errorMessage: string;
|
||||
processInstances: ProcessInstance[];
|
||||
data: ObjectDataTableAdapter;
|
||||
currentProcessInstanceId: string;
|
||||
|
||||
@Input()
|
||||
filter: FilterModel;
|
||||
|
||||
@Input()
|
||||
schemaColumn: any[] = [
|
||||
{type: 'text', key: 'id', title: 'Id', sortable: true},
|
||||
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
|
||||
{type: 'text', key: 'started', title: 'Started', sortable: true},
|
||||
{type: 'text', key: 'startedBy.email', title: 'Started By', sortable: true}
|
||||
];
|
||||
|
||||
@Output()
|
||||
rowClick: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
@Output()
|
||||
onSuccess: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
onError: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor (private processService: ActivitiProcessService, private translate: AlfrescoTranslationService) {
|
||||
if (translate !== null) {
|
||||
@ -51,27 +71,77 @@ export class ActivitiProcesslistComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getProcesses();
|
||||
this.data = new ObjectDataTableAdapter(
|
||||
[],
|
||||
this.schemaColumn
|
||||
);
|
||||
if (this.filter) {
|
||||
this.load(this.filter);
|
||||
}
|
||||
}
|
||||
|
||||
getProcesses() {
|
||||
this.processService.getProcesses()
|
||||
load(filter: FilterModel) {
|
||||
this.processService.getProcessInstances(filter)
|
||||
.subscribe(
|
||||
(processInstances) => {
|
||||
this.data = new ObjectDataTableAdapter(
|
||||
processInstances,
|
||||
[
|
||||
{type: 'text', key: 'id', title: 'Id', sortable: true},
|
||||
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
|
||||
{type: 'text', key: 'started', title: 'Started', sortable: true},
|
||||
{type: 'text', key: 'startedBy.email', title: 'Started By', sortable: true}
|
||||
]
|
||||
);
|
||||
this.renderProcessInstances(processInstances);
|
||||
this.onSuccess.emit(processInstances);
|
||||
},
|
||||
error => this.errorMessage = <any>error);
|
||||
error => {
|
||||
this.errorMessage = <any>error;
|
||||
this.onError.emit(error);
|
||||
});
|
||||
}
|
||||
|
||||
onItemClick(processInstance: ProcessInstance, event: any) {
|
||||
console.log(processInstance, event);
|
||||
reload() {
|
||||
this.load(this.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the process list
|
||||
*
|
||||
* @param processInstances
|
||||
*/
|
||||
private renderProcessInstances(processInstances: any[]) {
|
||||
processInstances = this.optimizeProcessNames(processInstances);
|
||||
this.data = new ObjectDataTableAdapter(
|
||||
processInstances,
|
||||
this.schemaColumn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the list is empty
|
||||
* @returns {ObjectDataTableAdapter|boolean}
|
||||
*/
|
||||
isListEmpty(): boolean {
|
||||
return this.data === undefined ||
|
||||
(this.data && this.data.getRows() && this.data.getRows().length === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit the event rowClick passing the current task id when the row is clicked
|
||||
* @param event
|
||||
*/
|
||||
onRowClick(event: DataRowEvent) {
|
||||
let item = event;
|
||||
this.currentProcessInstanceId = item.value.getValue('id');
|
||||
this.rowClick.emit(this.currentProcessInstanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize process name field
|
||||
* @param tasks
|
||||
* @returns {any[]}
|
||||
*/
|
||||
private optimizeProcessNames(tasks: any[]) {
|
||||
tasks = tasks.map(t => {
|
||||
t.name = t.name || 'No name';
|
||||
if (t.name.length > 50) {
|
||||
t.name = t.name.substring(0, 50) + '...';
|
||||
}
|
||||
return t;
|
||||
});
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.material-icons:hover {
|
||||
color: rgb(255, 152, 0);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<button type="button" (click)="showDialog()" class="mdl-button">{{'START_PROCESS.BUTTON'|translate}}</button>
|
||||
|
||||
<dialog class="mdl-dialog" #dialog>
|
||||
<h4 class="mdl-dialog__title">{{'START_PROCESS.DIALOG.TITLE'|translate}}</h4>
|
||||
<div class="mdl-dialog__content">
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||
<select name="processDefinition" [(ngModel)]="processDefinition" id="processDefinition">
|
||||
<option *ngFor="let processDef of processDefinitions" [value]="processDef.id">
|
||||
{{processDef.name}}
|
||||
</option>
|
||||
</select>
|
||||
<label class="mdl-textfield__label" for="processDefinition">{{'START_PROCESS.DIALOG.LABEL.TYPE'|translate}}</label>
|
||||
</div>
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||
<input class="mdl-textfield__input" type="text" [(ngModel)]="name" rows="1" id="processName" />
|
||||
<label class="mdl-textfield__label" for="processName">{{'START_PROCESS.DIALOG.LABEL.NAME'|translate}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdl-dialog__actions">
|
||||
<button type="button" (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>
|
||||
</div>
|
||||
</dialog>
|
@ -0,0 +1,101 @@
|
||||
/*!
|
||||
* @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, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoPipeTranslate } from 'ng2-alfresco-core';
|
||||
import { ActivitiProcessService } from './../services/activiti-process.service';
|
||||
|
||||
declare let componentHandler: any;
|
||||
declare let __moduleName: string;
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-start-process',
|
||||
moduleId: __moduleName,
|
||||
templateUrl: './activiti-start-process.component.html',
|
||||
styleUrls: ['./activiti-start-process.component.css'],
|
||||
providers: [ActivitiProcessService],
|
||||
pipes: [ AlfrescoPipeTranslate ]
|
||||
|
||||
})
|
||||
export class ActivitiStartProcessButton implements OnInit {
|
||||
|
||||
@Input()
|
||||
appId: string;
|
||||
|
||||
@ViewChild('dialog')
|
||||
dialog: any;
|
||||
|
||||
processDefinitions: any[] = [];
|
||||
|
||||
name: string;
|
||||
processDefinition: string;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param auth
|
||||
* @param translate
|
||||
* @param activitiProcess
|
||||
*/
|
||||
constructor(private auth: AlfrescoAuthenticationService,
|
||||
private translate: AlfrescoTranslationService,
|
||||
private activitiProcess: ActivitiProcessService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-processlist/src');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.load(this.appId);
|
||||
}
|
||||
|
||||
public load(appId: string) {
|
||||
this.activitiProcess.getProcessDefinitions(this.appId).subscribe(
|
||||
(res: any[]) => {
|
||||
this.processDefinitions = res;
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public showDialog() {
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.showModal();
|
||||
}
|
||||
}
|
||||
|
||||
public startProcess() {
|
||||
if (this.processDefinition && this.name) {
|
||||
this.activitiProcess.startProcess(this.processDefinition, this.name).subscribe(
|
||||
(res: any) => {
|
||||
this.cancel();
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
if (this.dialog) {
|
||||
this.dialog.nativeElement.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,54 @@
|
||||
{
|
||||
"PROCESSLIST": {
|
||||
"NONE": "No active processes were found",
|
||||
"SUMMARY": "Found {{total}} active process instances",
|
||||
"ERROR": "An error occurred while loading the processes: {{errorMessage}}",
|
||||
"NONE": "No process instances were found",
|
||||
"SUMMARY": "Found {{total}} process instances",
|
||||
"ERROR": "An error occurred while loading the processes instances: {{errorMessage}}",
|
||||
"COLUMN": {
|
||||
"NAME": "Name"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "No process instance filter selected."
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"STARTED_BY": "Started by",
|
||||
"STARTED": "Started",
|
||||
"COMMENTS": "Comments",
|
||||
"TASKS_ACTIVE": "Active Tasks",
|
||||
"TASKS_COMPLETED": "Completed Tasks",
|
||||
"TASK_SUBTITLE": "Assigned to {{user}}, created {{created}}"
|
||||
},
|
||||
"BUTTON": {
|
||||
"CANCEL": "Cancel Process"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "No process details found."
|
||||
},
|
||||
"TASKS": {
|
||||
"NO_ACTIVE": "No tasks are currently active",
|
||||
"NO_COMPLETED": "No tasks have been completed yet",
|
||||
"TASK_DETAILS": "Task details",
|
||||
"TASK_CLOSE": "Close"
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "No comments."
|
||||
}
|
||||
},
|
||||
"START_PROCESS": {
|
||||
"BUTTON": "Start Process",
|
||||
"DIALOG": {
|
||||
"TITLE": "Start Process",
|
||||
"LABEL": {
|
||||
"TYPE": "Type",
|
||||
"NAME": "Name"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Start",
|
||||
"CANCEL": "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Comment submitted against a process
|
||||
*
|
||||
* @returns {Comment} .
|
||||
*/
|
||||
import { User } from './user.model';
|
||||
|
||||
export class Comment {
|
||||
id: number;
|
||||
message: string;
|
||||
created: string;
|
||||
createdBy: User;
|
||||
|
||||
constructor(id: number, message: string, created: string, createdBy: User) {
|
||||
this.id = id;
|
||||
this.message = message;
|
||||
this.created = created;
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* This object represent the filter.
|
||||
*
|
||||
*
|
||||
* @returns {FilterModel} .
|
||||
*/
|
||||
export class FilterModel {
|
||||
id: number;
|
||||
name: string;
|
||||
recent: boolean = false;
|
||||
icon: string;
|
||||
filter: FilterParamsModel;
|
||||
appId: number;
|
||||
|
||||
constructor(name: string, recent: boolean, icon: string, query: string, state: string, assignment: string, appDefinitionId?: string) {
|
||||
this.name = name;
|
||||
this.recent = recent;
|
||||
this.icon = icon;
|
||||
this.filter = new FilterParamsModel(query, state, assignment, appDefinitionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This object represent the parameters of a filter.
|
||||
*
|
||||
*
|
||||
* @returns {FilterModel} .
|
||||
*/
|
||||
export class FilterParamsModel {
|
||||
name: string;
|
||||
sort: string;
|
||||
state: string;
|
||||
appDefinitionId: string;
|
||||
|
||||
constructor(query: string, sort: string, state: string, appDefinitionId?: string) {
|
||||
this.name = query;
|
||||
this.sort = sort;
|
||||
this.state = state;
|
||||
this.appDefinitionId = appDefinitionId;
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* This object represent the details of a task.
|
||||
*
|
||||
*
|
||||
* @returns {TaskDetailsModel} .
|
||||
*/
|
||||
import { User } from './user.model';
|
||||
|
||||
export class TaskDetailsModel {
|
||||
id: string;
|
||||
name: string;
|
||||
assignee: User;
|
||||
priority: number;
|
||||
adhocTaskCanBeReassigned: number;
|
||||
category: string;
|
||||
created: string;
|
||||
description: string;
|
||||
dueDate: string;
|
||||
duration: string;
|
||||
endDate: string;
|
||||
executionId: string;
|
||||
formKey: string;
|
||||
initiatorCanCompleteTask: boolean = false;
|
||||
managerOfCandidateGroup: boolean = false;
|
||||
memberOfCandidateGroup: boolean = false;
|
||||
memberOfCandidateUsers: boolean = false;
|
||||
involvedPeople: User [];
|
||||
parentTaskId: string;
|
||||
parentTaskName: string;
|
||||
processDefinitionCategory: string;
|
||||
processDefinitionDeploymentId: string;
|
||||
processDefinitionDescription: string;
|
||||
processDefinitionId: string;
|
||||
processDefinitionKey: string;
|
||||
processDefinitionName: string;
|
||||
processDefinitionVersion: number = 0;
|
||||
processInstanceId: string;
|
||||
processInstanceName: string;
|
||||
processInstanceStartUserId: string;
|
||||
taskDefinitionKey: string;
|
||||
|
||||
|
||||
constructor(obj: any) {
|
||||
this.id = obj.id;
|
||||
this.name = obj.name;
|
||||
this.priority = obj.priority;
|
||||
this.assignee = new User(obj.assignee.id, obj.assignee.email, obj.assignee.firstName, obj.assignee.lastName);
|
||||
this.adhocTaskCanBeReassigned = obj.adhocTaskCanBeReassigned;
|
||||
this.created = obj.created;
|
||||
this.description = obj.description;
|
||||
this.dueDate = obj.dueDate;
|
||||
this.duration = obj.duration;
|
||||
this.endDate = obj.endDate;
|
||||
this.executionId = obj.executionId;
|
||||
this.formKey = obj.formKey;
|
||||
this.initiatorCanCompleteTask = obj.initiatorCanCompleteTask;
|
||||
this.managerOfCandidateGroup = obj.managerOfCandidateGroup;
|
||||
this.memberOfCandidateGroup = obj.memberOfCandidateGroup;
|
||||
this.memberOfCandidateUsers = obj.memberOfCandidateUsers;
|
||||
this.involvedPeople = obj.involvedPeople;
|
||||
this.parentTaskId = obj.parentTaskId;
|
||||
this.parentTaskName = obj.parentTaskName;
|
||||
this.processDefinitionCategory = obj.processDefinitionCategory;
|
||||
this.processDefinitionDeploymentId = obj.processDefinitionDeploymentId;
|
||||
this.processDefinitionDescription = obj.processDefinitionDescription;
|
||||
this.processDefinitionId = obj.processDefinitionId;
|
||||
this.processDefinitionKey = obj.processDefinitionKey;
|
||||
this.processDefinitionName = obj.processDefinitionName;
|
||||
this.processDefinitionVersion = obj.processDefinitionVersion;
|
||||
this.processInstanceId = obj.processInstanceId;
|
||||
this.processInstanceName = obj.processInstanceName;
|
||||
this.processInstanceStartUserId = obj.processInstanceStartUserId;
|
||||
this.taskDefinitionKey = obj.taskDefinitionKey;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* This object represent the user.
|
||||
*
|
||||
*
|
||||
* @returns {User} .
|
||||
*/
|
||||
|
||||
export class User {
|
||||
id: number;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
|
||||
constructor(id: number, email: string, firstName: string, lastName: string) {
|
||||
this.id = id;
|
||||
this.email = email;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
@ -17,6 +17,9 @@
|
||||
|
||||
import {AlfrescoAuthenticationService} from 'ng2-alfresco-core';
|
||||
import {ProcessInstance} from '../models/process-instance';
|
||||
import {FilterModel} from '../models/filter.model';
|
||||
import {User} from '../models/user.model';
|
||||
import {Comment} from '../models/comment.model';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/map';
|
||||
@ -28,6 +31,16 @@ export class ActivitiProcessService {
|
||||
constructor(public authService: AlfrescoAuthenticationService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive all the Deployed app
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
getDeployedApplications(name: string): Observable<any> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.appsApi.getAppDefinitions())
|
||||
.map((response: any) => response.data.find(p => p.name === name))
|
||||
.do(data => console.log('Application: ' + JSON.stringify(data)));
|
||||
}
|
||||
|
||||
getProcesses(): Observable<ProcessInstance[]> {
|
||||
let request = {'page': 0, 'sort': 'created-desc', 'state': 'all'};
|
||||
|
||||
@ -36,6 +49,109 @@ export class ActivitiProcessService {
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcessInstances(filter: FilterModel): Observable<ProcessInstance[]> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessInstances(filter))
|
||||
.map(this.extractData)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcessFilters(appId: string): Observable<any[]> {
|
||||
let filterOpts = appId ? {
|
||||
appId: appId
|
||||
} : {};
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.userFiltersApi.getUserProcessInstanceFilters(filterOpts))
|
||||
.map(this.extractData)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcess(id: string): Observable<ProcessInstance> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.processApi.getProcessInstance(id))
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getProcessTasks(id: string, state: string): Observable<any[]> {
|
||||
let taskOpts = state ? {
|
||||
processInstanceId: id,
|
||||
state: state
|
||||
} : {
|
||||
processInstanceId: id
|
||||
};
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.taskApi.listTasks(taskOpts))
|
||||
.map(this.extractData)
|
||||
.map(tasks => tasks.map((task: any) => {
|
||||
task.created = new Date(task.created);
|
||||
return task;
|
||||
}))
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive all the process instance's comments
|
||||
* @param id - process instance ID
|
||||
* @returns {<Comment[]>}
|
||||
*/
|
||||
getProcessInstanceComments(id: string): Observable<Comment[]> {
|
||||
return Observable.fromPromise(this.authService.getAlfrescoApi().activiti.commentsApi.getProcessInstanceComments(id))
|
||||
.map(res => res)
|
||||
.map((response: any) => {
|
||||
let comments: Comment[] = [];
|
||||
response.data.forEach((comment) => {
|
||||
let user = new User(
|
||||
comment.createdBy.id, comment.createdBy.email, comment.createdBy.firstName, comment.createdBy.lastName);
|
||||
comments.push(new Comment(comment.id, comment.message, comment.created, user));
|
||||
});
|
||||
return comments;
|
||||
}).catch(this.handleError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment to a process instance
|
||||
* @param id - process instance Id
|
||||
* @param message - content of the comment
|
||||
* @returns {Comment}
|
||||
*/
|
||||
addProcessInstanceComment(id: string, message: string): Observable<Comment> {
|
||||
return Observable.fromPromise(
|
||||
this.authService.getAlfrescoApi().activiti.commentsApi.addProcessInstanceComment({message: message}, id)
|
||||
)
|
||||
.map(res => res)
|
||||
.map((response: Comment) => {
|
||||
return new Comment(response.id, response.message, response.created, response.createdBy);
|
||||
}).catch(this.handleError);
|
||||
|
||||
}
|
||||
|
||||
getProcessDefinitions(appId: string) {
|
||||
let opts = appId ? {
|
||||
latest: true,
|
||||
appId: appId
|
||||
} : {
|
||||
latest: true
|
||||
};
|
||||
return Observable.fromPromise(
|
||||
this.authService.getAlfrescoApi().activiti.processApi.getProcessDefinitions(opts)
|
||||
)
|
||||
.map(this.extractData)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
startProcess(processDefinitionId: string, name: string) {
|
||||
let startRequest: any = {};
|
||||
startRequest.name = name;
|
||||
startRequest.processDefinitionId = processDefinitionId;
|
||||
return Observable.fromPromise(
|
||||
this.authService.getAlfrescoApi().activiti.processApi.startNewProcessInstance(startRequest)
|
||||
)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
cancelProcess(processInstanceId: string) {
|
||||
return Observable.fromPromise(
|
||||
this.authService.getAlfrescoApi().activiti.processApi.deleteProcessInstance(processInstanceId)
|
||||
)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
private extractData(res: any) {
|
||||
return res.data || {};
|
||||
}
|
||||
|
@ -37,8 +37,8 @@
|
||||
"material-design-lite": "1.1.3",
|
||||
"ng2-translate": "2.2.2",
|
||||
"alfresco-js-api": "^0.3.0",
|
||||
"ng2-alfresco-datatable": "^0.1.12",
|
||||
"ng2-alfresco-core": "^0.1.36"
|
||||
"ng2-alfresco-datatable": "^0.3.0",
|
||||
"ng2-alfresco-core": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browser-sync": "2.10.0",
|
||||
|
@ -15,69 +15,70 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ALFRESCO_CORE_PROVIDERS, AlfrescoAuthenticationService, AlfrescoSettingsService} from 'ng2-alfresco-core';
|
||||
import { bootstrap } from '@angular/platform-browser-dynamic';
|
||||
import {ActivitiTaskList} from 'ng2-activiti-tasklist';
|
||||
import {ObjectDataTableAdapter, ObjectDataColumn} from 'ng2-alfresco-datatable';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { ALFRESCO_CORE_PROVIDERS, AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
|
||||
import { ALFRESCO_TASKLIST_DIRECTIVES } from 'ng2-activiti-tasklist';
|
||||
import { HTTP_PROVIDERS } from '@angular/http';
|
||||
|
||||
declare let AlfrescoApi: any;
|
||||
import { ATIVITI_FORM_PROVIDERS } from 'ng2-activiti-form';
|
||||
|
||||
@Component({
|
||||
selector: 'activiti-tasklist-demo',
|
||||
template: `label for="token"><b>Insert a valid access token / ticket:</b></label><br>
|
||||
template: `<label for="token"><b>Insert a valid access token / ticket:</b></label><br>
|
||||
<input id="token" type="text" size="48" (change)="updateToken();documentList.reload()" [(ngModel)]="token"><br>
|
||||
<label for="token"><b>Insert the ip of your Alfresco instance:</b></label><br>
|
||||
<label for="token"><b>Insert the ip of your Activiti instance:</b></label><br>
|
||||
<input id="token" type="text" size="48" (change)="updateHost();documentList.reload()" [(ngModel)]="bpmHost"><br><br>
|
||||
<div *ngIf="!authenticated" style="color:#FF2323">
|
||||
Authentication failed to ip {{ bpmHost }} with user: admin, admin, you can still try to add a valid token to perform
|
||||
operations.
|
||||
</div>
|
||||
<hr>
|
||||
<label for="token"><b>Insert a scriptPath</b></label><br>
|
||||
<input id="token" type="text" size="48" [(ngModel)]="scriptPath"><br>
|
||||
<label for="token"><b>Insert a contextRoot</b></label><br>
|
||||
<input id="token" type="text" size="48" [(ngModel)]="contextRoot"><br>
|
||||
<label for="token"><b>Insert a servicePath</b></label><br>
|
||||
<input id="token" type="text" size="48" [(ngModel)]="servicePath"><br>
|
||||
<div class="container" *ngIf="authenticated">
|
||||
<activiti-tasklist></activiti-tasklist>
|
||||
<span>Task Filters</span>
|
||||
<activiti-filters (filterClick)="onFilterClick($event)"></activiti-filters>
|
||||
<span>Tasks</span>
|
||||
<activiti-tasklist [taskFilter]="taskFilter" [schemaColumn]="schemaColumn"
|
||||
(rowClick)="onRowClick($event)" #activititasklist></activiti-tasklist>
|
||||
<span>Task Details</span>
|
||||
<activiti-task-details [taskId]="currentTaskId" #activitidetails></activiti-task-details>
|
||||
</div>`,
|
||||
styles: [
|
||||
':host > .container {padding: 10px}',
|
||||
'.p-10 { padding: 10px; }'
|
||||
],
|
||||
directives: [ActivitiTaskList]
|
||||
directives: [ALFRESCO_TASKLIST_DIRECTIVES]
|
||||
})
|
||||
class ActivitiTaskListDemo implements OnInit {
|
||||
|
||||
@ViewChild('activititasklist')
|
||||
activititasklist: any;
|
||||
|
||||
@ViewChild('activitidetails')
|
||||
activitidetails: any;
|
||||
|
||||
bpmHost: string = 'http://127.0.0.1:9999';
|
||||
|
||||
token: string;
|
||||
|
||||
data: ObjectDataTableAdapter;
|
||||
|
||||
authenticated: boolean;
|
||||
|
||||
schemaColumn: any [] = [];
|
||||
|
||||
currentTaskId: string;
|
||||
|
||||
taskFilter: any;
|
||||
|
||||
constructor(private authService: AlfrescoAuthenticationService,
|
||||
private settingsService: AlfrescoSettingsService) {
|
||||
this.settingsService.setProviders('BPM');
|
||||
this.data = new ObjectDataTableAdapter([], []);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.login();
|
||||
|
||||
let schema = [
|
||||
{type: 'text', key: 'id', title: 'Id'},
|
||||
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
|
||||
{type: 'text', key: 'formKey', title: 'Form Key', sortable: true},
|
||||
{type: 'text', key: 'created', title: 'Created', sortable: true}
|
||||
this.schemaColumn = [
|
||||
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}
|
||||
];
|
||||
|
||||
let columns = schema.map(col => new ObjectDataColumn(col));
|
||||
this.data.setColumns(columns);
|
||||
}
|
||||
|
||||
login() {
|
||||
@ -92,9 +93,20 @@ class ActivitiTaskListDemo implements OnInit {
|
||||
this.authenticated = false;
|
||||
});
|
||||
}
|
||||
|
||||
onFilterClick(event: any) {
|
||||
this.taskFilter = event;
|
||||
this.activititasklist.load(this.taskFilter);
|
||||
}
|
||||
|
||||
onRowClick(taskId) {
|
||||
this.currentTaskId = taskId;
|
||||
this.activitidetails.loadDetails(this.currentTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
bootstrap(ActivitiTaskListDemo, [
|
||||
HTTP_PROVIDERS,
|
||||
ATIVITI_FORM_PROVIDERS,
|
||||
ALFRESCO_CORE_PROVIDERS]
|
||||
);
|
||||
|
@ -13,6 +13,7 @@
|
||||
'ng2-translate': 'node_modules/ng2-translate',
|
||||
'ng2-alfresco-core': 'node_modules/ng2-alfresco-core/dist',
|
||||
'ng2-alfresco-datatable': 'node_modules/ng2-alfresco-datatable/dist',
|
||||
'ng2-activiti-form': 'node_modules/ng2-activiti-form/dist',
|
||||
'ng2-activiti-tasklist': 'node_modules/ng2-activiti-tasklist/dist'
|
||||
};
|
||||
// packages tells the System loader how to load when no filename and/or no extension
|
||||
@ -24,6 +25,7 @@
|
||||
'ng2-translate': { defaultExtension: 'js' },
|
||||
'ng2-alfresco-core': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-alfresco-datatable': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-activiti-form': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-activiti-tasklist': { main: 'index.js', defaultExtension: 'js' }
|
||||
};
|
||||
var ngPackageNames = [
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ng2-activiti-tasklist",
|
||||
"description": "Activiti Angular2 Task List Component",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
@ -67,9 +67,9 @@
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "0.6.12",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0",
|
||||
"ng2-alfresco-datatable": "0.2.0",
|
||||
"ng2-activiti-form": "0.2.0",
|
||||
"ng2-alfresco-core": "0.3.0",
|
||||
"ng2-alfresco-datatable": "0.3.0",
|
||||
"ng2-activiti-form": "0.3.0",
|
||||
"alfresco-js-api": "^0.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -59,7 +59,7 @@ export class ActivitiChecklist implements OnInit {
|
||||
private activitiTaskList: ActivitiTaskListService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
this.task$ = new Observable<TaskDetailsModel>(observer => this.taskObserver = observer).share();
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ export class ActivitiComments implements OnInit {
|
||||
private activitiTaskList: ActivitiTaskListService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
|
||||
this.comment$ = new Observable<Comment>(observer => this.commentObserver = observer).share();
|
||||
|
@ -70,7 +70,7 @@ export class ActivitiFilters implements OnInit {
|
||||
this.filter$ = new Observable<FilterModel>(observer => this.filterObserver = observer).share();
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ export class ActivitiPeople implements OnInit {
|
||||
private translate: AlfrescoTranslationService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
this.people$ = new Observable<User>(observer => this.peopleObserver = observer).share();
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ export class ActivitiTaskDetails implements OnInit {
|
||||
private activitiTaskList: ActivitiTaskListService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +125,8 @@ export class ActivitiTaskDetails implements OnInit {
|
||||
console.log(this.taskDetails);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.taskDetails = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ export class ActivitiTaskHeader implements OnInit, OnChanges {
|
||||
private translate: AlfrescoTranslationService) {
|
||||
|
||||
if (translate) {
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist');
|
||||
translate.addTranslationFolder('node_modules/ng2-activiti-tasklist/src');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ng2-alfresco-core",
|
||||
"description": "Alfresco Angular 2 Components core",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
|
@ -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;
|
||||
|
@ -41,8 +41,7 @@
|
||||
"license-check": "1.1.5",
|
||||
|
||||
"material-design-icons": "2.2.3",
|
||||
"material-design-lite": "1.1.3",
|
||||
"ng2-activiti-processlist": "^0.1.0"
|
||||
"material-design-lite": "1.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browser-sync": "2.10.0",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ng2-alfresco-datatable",
|
||||
"description": "Alfresco Angular2 DataTable Component",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
@ -63,7 +63,7 @@
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "0.6.12",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0"
|
||||
"ng2-alfresco-core": "0.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"material-design-icons": "^2.2.3",
|
||||
|
@ -47,7 +47,11 @@
|
||||
[context-menu]="getContextMenuActions(row, col)">
|
||||
<div *ngSwitchCase="'image'" class="cell-value">
|
||||
<i *ngIf="isIconValue(row, col)" class="material-icons icon-cell">{{asIconValue(row, col)}}</i>
|
||||
<img *ngIf="!isIconValue(row, col)" class="image-cell" alt="{{iconAltTextKey(data.getValue(row, col))|translate}}" src="{{data.getValue(row, col)}}">
|
||||
<img *ngIf="!isIconValue(row, col)"
|
||||
class="image-cell"
|
||||
alt="{{iconAltTextKey(data.getValue(row, col))|translate}}"
|
||||
src="{{data.getValue(row, col)}}"
|
||||
(error)="onImageLoadingError($event)">
|
||||
</div>
|
||||
<div *ngSwitchCase="'date'" class="cell-value" [attr.data-automation-id]="'date_' + data.getValue(row, col)">
|
||||
{{data.getValue(row, col)}}
|
||||
|
@ -320,4 +320,29 @@ describe('DataTable', () => {
|
||||
expect(dataTable.isColumnSorted(<DataColumn> {key: 'column_1'}, 'asc')).toBeTruthy();
|
||||
expect(dataTable.isColumnSorted(<DataColumn> {key: 'column_2'}, 'desc')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should replace image source with fallback thumbnail on error', () => {
|
||||
let event = <any> {
|
||||
srcElement: {
|
||||
src: 'missing-image'
|
||||
}
|
||||
};
|
||||
|
||||
dataTable.fallbackThumbnail = '<fallback>';
|
||||
dataTable.onImageLoadingError(event);
|
||||
expect(event.srcElement.src).toBe(dataTable.fallbackThumbnail);
|
||||
});
|
||||
|
||||
it('should replace image source only when fallback available', () => {
|
||||
const originalSrc = 'missing-image';
|
||||
let event = <any> {
|
||||
srcElement: {
|
||||
src: originalSrc
|
||||
}
|
||||
};
|
||||
|
||||
dataTable.fallbackThumbnail = null;
|
||||
dataTable.onImageLoadingError(event);
|
||||
expect(event.srcElement.src).toBe(originalSrc);
|
||||
});
|
||||
});
|
||||
|
@ -63,6 +63,9 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
@Input()
|
||||
actions: boolean = false;
|
||||
|
||||
@Input()
|
||||
fallbackThumbnail: string;
|
||||
|
||||
@Output()
|
||||
rowClick: EventEmitter<DataRowEvent> = new EventEmitter<DataRowEvent>();
|
||||
|
||||
@ -155,6 +158,13 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
}
|
||||
}
|
||||
|
||||
onImageLoadingError(event: Event) {
|
||||
if (event && this.fallbackThumbnail) {
|
||||
let element = <any> event.srcElement;
|
||||
element.src = this.fallbackThumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
isIconValue(row: DataRow, col: DataColumn) {
|
||||
if (row && col) {
|
||||
let value = row.getValue(col.key);
|
||||
|
@ -12,6 +12,10 @@
|
||||
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css">
|
||||
|
||||
<!-- 1. Load libraries -->
|
||||
<!-- Polyfill(s) for Safari (pre-10.x) -->
|
||||
<script src="node_modules/intl/dist/Intl.min.js"></script>
|
||||
<script src="node_modules/intl/locale-data/jsonp/en.js"></script>
|
||||
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
|
@ -36,10 +36,11 @@
|
||||
"material-design-icons": "2.2.3",
|
||||
"material-design-lite": "1.1.3",
|
||||
"ng2-translate": "2.2.2",
|
||||
"intl": "1.2.4",
|
||||
"alfresco-js-api": "^0.3.0",
|
||||
"ng2-alfresco-core": "^0.2.0",
|
||||
"ng2-alfresco-documentlist": "^0.2.0",
|
||||
"ng2-alfresco-datatable": "^0.2.0"
|
||||
"ng2-alfresco-core": "^0.3.0",
|
||||
"ng2-alfresco-documentlist": "^0.3.0",
|
||||
"ng2-alfresco-datatable": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "2.0.0",
|
||||
|
@ -37,17 +37,15 @@ import {
|
||||
@Component({
|
||||
selector: 'alfresco-documentlist-demo',
|
||||
template: `
|
||||
<label for="token"><b>Insert a valid access token / ticket:</b></label><br>
|
||||
<input id="token" type="text" size="48" (change)="updateToken();documentList.reload()" [(ngModel)]="token"><br>
|
||||
<label for="token"><b>Insert the ip of your Alfresco instance:</b></label><br>
|
||||
<input id="token" type="text" size="48" (change)="updateHost();documentList.reload()" [(ngModel)]="host"><br><br>
|
||||
<label for="ticket"><b>Insert a valid access ticket / ticket:</b></label><br>
|
||||
<input id="ticket" type="text" size="48" (change)="updateTicket(); documentList.reload()" [(ngModel)]="ticket"><br>
|
||||
<label for="host"><b>Insert the ip of your Alfresco instance:</b></label><br>
|
||||
<input id="host" type="text" size="48" (change)="updateHost(); documentList.reload()" [(ngModel)]="ecmHost"><br><br>
|
||||
<div *ngIf="!authenticated" style="color:#FF2323">
|
||||
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid token to perform
|
||||
Authentication failed to ip {{ ecmHost }} with user: admin, admin, you can still try to add a valid ticket to perform
|
||||
operations.
|
||||
</div>
|
||||
<hr>
|
||||
<div class="container" *ngIf="authenticated">
|
||||
|
||||
<alfresco-document-list-breadcrumb
|
||||
[currentFolderPath]="currentPath"
|
||||
[target]="documentList">
|
||||
@ -57,7 +55,6 @@ import {
|
||||
[currentFolderPath]="currentPath"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="true"
|
||||
[multiselect]="true"
|
||||
(folderChange)="onFolderChanged($event)">
|
||||
<!--
|
||||
<empty-folder-content>
|
||||
@ -74,6 +71,12 @@ import {
|
||||
sortable="true"
|
||||
class="full-width ellipsis-cell">
|
||||
</content-column>
|
||||
<!--
|
||||
<content-column
|
||||
title="Type"
|
||||
source="content.mimeType">
|
||||
</content-column>
|
||||
-->
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_BY' | translate}}"
|
||||
key="createdByUser.displayName"
|
||||
@ -89,6 +92,7 @@ import {
|
||||
class="desktop-only">
|
||||
</content-column>
|
||||
</content-columns>
|
||||
|
||||
<content-actions>
|
||||
<!-- folder actions -->
|
||||
<content-action
|
||||
@ -106,7 +110,6 @@ import {
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.DELETE' | translate}}"
|
||||
handler="delete">
|
||||
</content-action>
|
||||
|
||||
<!-- document actions -->
|
||||
<content-action
|
||||
target="document"
|
||||
@ -128,10 +131,14 @@ import {
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DELETE' | translate}}"
|
||||
handler="delete">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
title="Activiti: View Form"
|
||||
(execute)="viewActivitiForm($event)">
|
||||
</content-action>
|
||||
</content-actions>
|
||||
</alfresco-document-list>
|
||||
<context-menu-holder></context-menu-holder>
|
||||
</div>
|
||||
`,
|
||||
styles: [':host > .container {padding: 10px}'],
|
||||
directives: [DOCUMENT_LIST_DIRECTIVES, CONTEXT_MENU_DIRECTIVES],
|
||||
@ -141,28 +148,27 @@ import {
|
||||
class DocumentListDemo implements OnInit {
|
||||
|
||||
currentPath: string = '/';
|
||||
authenticated: boolean;
|
||||
|
||||
authenticated: boolean = false;
|
||||
ecmHost: string = 'http://devproducts-platform.alfresco.me';
|
||||
|
||||
token: string;
|
||||
ticket: string;
|
||||
|
||||
constructor(
|
||||
private authService: AlfrescoAuthenticationService,
|
||||
private settingsService: AlfrescoSettingsService,
|
||||
translation: AlfrescoTranslationService,
|
||||
private documentActions: DocumentActionsService) {
|
||||
constructor(private authService: AlfrescoAuthenticationService, private settingsService: AlfrescoSettingsService,
|
||||
translation: AlfrescoTranslationService, private documentActions: DocumentActionsService) {
|
||||
|
||||
settingsService.ecmHost = this.ecmHost;
|
||||
if (this.authService.getTicket()) {
|
||||
this.token = this.authService.getTicket();
|
||||
settingsService.setProviders('ECM');
|
||||
|
||||
if (this.authService.getTicketEcm()) {
|
||||
this.ticket = this.authService.getTicketEcm();
|
||||
}
|
||||
|
||||
translation.addTranslationFolder();
|
||||
documentActions.setHandler('my-handler', this.myDocumentActionHandler.bind(this));
|
||||
}
|
||||
|
||||
public updateToken(): void {
|
||||
localStorage.setItem('token', this.token);
|
||||
public updateTicket(): void {
|
||||
localStorage.setItem('ticket-ECM', this.ticket);
|
||||
}
|
||||
|
||||
public updateHost(): void {
|
||||
@ -190,9 +196,9 @@ class DocumentListDemo implements OnInit {
|
||||
|
||||
login() {
|
||||
this.authService.login('admin', 'admin').subscribe(
|
||||
token => {
|
||||
console.log(token);
|
||||
this.token = token;
|
||||
ticket => {
|
||||
console.log(ticket);
|
||||
this.ticket = this.authService.getTicketEcm();
|
||||
this.authenticated = true;
|
||||
},
|
||||
error => {
|
||||
|
@ -72,7 +72,7 @@ module.exports = function (config) {
|
||||
],
|
||||
|
||||
// Coverage reporter generates the coverage
|
||||
reporters: ['mocha', 'coverage', 'coveralls', 'kjhtml'],
|
||||
reporters: ['mocha', 'coverage', 'kjhtml'],
|
||||
|
||||
// Source files that you wanna generate coverage for.
|
||||
// Do not include tests or libraries (these files will be instrumented by Istanbul)
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ng2-alfresco-documentlist",
|
||||
"description": "Alfresco Angular2 Document List Component",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"scripts": {
|
||||
"postinstall": "typings install",
|
||||
@ -70,8 +70,8 @@
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "0.6.12",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0",
|
||||
"ng2-alfresco-datatable": "0.2.0",
|
||||
"ng2-alfresco-core": "0.3.0",
|
||||
"ng2-alfresco-datatable": "0.3.0",
|
||||
"alfresco-js-api": "^0.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -0,0 +1,44 @@
|
||||
.document-list_empty_template {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.document-list__this-space-is-empty {
|
||||
height: 32px;
|
||||
opacity: 0.26;
|
||||
font-family: Muli, Helvetica, Arial, sans-serif;
|
||||
font-size: 24px;
|
||||
line-height: 1.33;
|
||||
letter-spacing: -1px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.document-list__drag-drop {
|
||||
height: 56px;
|
||||
opacity: 0.54;
|
||||
font-family: Muli, Helvetica, Arial, sans-serif;
|
||||
font-size: 56px;
|
||||
line-height: 1;
|
||||
letter-spacing: -2px;
|
||||
color: #000000;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.document-list__any-files-here-to-add {
|
||||
height: 24px;
|
||||
opacity: 0.54;
|
||||
font-family: Muli, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
letter-spacing: -0.4px;
|
||||
color: #000000;
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
.document-list__empty_doc_lib {
|
||||
width: 565px;
|
||||
height: 161px;
|
||||
object-fit: contain;
|
||||
margin-top: 17px;
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
[data]="data"
|
||||
[actions]="contentActions"
|
||||
[multiselect]="multiselect"
|
||||
[fallbackThumbnail]="baseComponentPath + '/img/ft_ic_miscellaneous.svg'"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||
(executeRowAction)="onExecuteRowAction($event)"
|
||||
@ -9,7 +10,12 @@
|
||||
(rowDblClick)="onRowDblClick($event)">
|
||||
<no-content-template>
|
||||
<template>
|
||||
<img [src]="baseComponentPath + '/img/document-list.empty-folder.png'">
|
||||
<div class="document-list_empty_template">
|
||||
<div class="document-list__this-space-is-empty">This folder is empty</div>
|
||||
<div class="document-list__drag-drop">Drag and Drop</div>
|
||||
<div class="document-list__any-files-here-to-add">any files here to add</div>
|
||||
<img [src]="baseComponentPath + '/img/empty_doc_lib.svg'" class="document-list__empty_doc_lib">
|
||||
</div>
|
||||
</template>
|
||||
</no-content-template>
|
||||
</alfresco-datatable>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user