src/lib/service/bpm/bpm.service.ts
BpmService
handles interaction related to BPM tasks.
The main parts provided and used by this service are Processes and WorkItems. Processes are defined on the backend side. They describe a set of tasks that will be executed by the process. Tasks that require user interaction are referred to as WorkItems.
Processes can be related to a special object type, but they don't have to. In addition to that they can refer to dms objects.
constructor(capabilities: CapabilitiesService, backend: BackendService, eventService: EventService, inboxService: InboxService)
|
|||||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:37
|
|||||||||||||||
Parameters :
|
addFileElements | ||||||||||||||||
addFileElements(processId: string, workItemId: string, elements: DmsObject[])
|
||||||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:318
|
||||||||||||||||
Add contents to a work items file.
Parameters :
Returns :
Observable<WorkItem>
The updated WorkItem |
addFileElementsFromClipboard | ||||||||||||
addFileElementsFromClipboard(workItem: WorkItem, clipboard: Clipboard)
|
||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:346
|
||||||||||||
Add a objects from the clipboard to a WorkItem.
Parameters :
Returns :
Observable<WorkItem>
The updated WorkItem |
fetchProcessModels |
fetchProcessModels()
|
Defined in src/lib/service/bpm/bpm.service.ts:335
|
Fetch all available bpm projects including all of their model data
Returns :
Observable<>
list of all the projects including the models |
forwardWorkItem | ||||||||||||
forwardWorkItem(item: WorkItem, action?: WorkItemAction)
|
||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:225
|
||||||||||||
Forwards a work item. If a WorkItem provides different actions (@link WorkItemAction) you can provide the selected action too.
Parameters :
Returns :
Observable<any>
|
getExecutableProcesses | ||||||||||||||||||||||||
getExecutableProcesses(types?: string[], useCached?: boolean, additionalData?: boolean, modelid?: string, global?: boolean)
|
||||||||||||||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:72
|
||||||||||||||||||||||||
Getter for the executable Processes. If types are provided, you'll get only the processes that are executable for all of them
Parameters :
Returns :
Observable<ExecutableProcess[]>
List of executable processes |
getExecutableProcessesForDmsObjects | ||||||||
getExecutableProcessesForDmsObjects(dmsObjects: DmsObject[])
|
||||||||
Defined in src/lib/service/bpm/bpm.service.ts:91
|
||||||||
Gets executable Processes for a given set of dms object.You'll get only the processes that are executable for all of them.
Parameters :
Returns :
Observable<ExecutableProcess[]>
List of executable processes |
getProcessData | ||||||
getProcessData(id: string)
|
||||||
Defined in src/lib/service/bpm/bpm.service.ts:95
|
||||||
Parameters :
Returns :
Observable<ProcessItem[]>
|
getProcesses | ||||||||||
getProcesses(size: number)
|
||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:51
|
||||||||||
Retrieve all processes of the current user.
Parameters :
Returns :
Observable<Process[]>
List of Processes |
getProcessFile | ||||||||
getProcessFile(processId: string)
|
||||||||
Defined in src/lib/service/bpm/bpm.service.ts:164
|
||||||||
Getter for a processes file. The file of a process contains dms objects attached to the process.
Parameters :
Returns :
Observable<FileEntry[]>
|
getProcessHistory | ||||||||
getProcessHistory(processId: string)
|
||||||||
Defined in src/lib/service/bpm/bpm.service.ts:294
|
||||||||
Returns the history for a process. Which entries are returned depends on the permissions of the current user.
Parameters :
Returns :
Observable<WorkItemHistoryEntry[]>
Observable<WorkItemHistoryEntry[]> |
getWorkItem | ||||||||||||||||
getWorkItem(processId: string, itemId: string, options?: any)
|
||||||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:188
|
||||||||||||||||
Retrieves a work item.
Parameters :
Returns :
Observable<WorkItem>
a WorkItem |
initExecutableProcesses |
initExecutableProcesses()
|
Defined in src/lib/service/bpm/bpm.service.ts:80
|
Returns :
Observable<any>
|
lockWorkItem | ||||||||
lockWorkItem(item: WorkItem)
|
||||||||
Defined in src/lib/service/bpm/bpm.service.ts:245
|
||||||||
Locks a WorkItem for the current user (personalization), meaning that the current user is now in charge of fulfilling the WorkItem task.
Parameters :
Returns :
Observable<WorkItem>
The updated WorkItem |
removeFileElement | ||||||||||||||||
removeFileElement(processId: string, workItemId: string, workItemContentId: string)
|
||||||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:306
|
||||||||||||||||
Removes a content from the work items file.
Parameters :
Returns :
Observable<any>
|
saveWorkItem | ||||||||
saveWorkItem(item: WorkItem)
|
||||||||
Defined in src/lib/service/bpm/bpm.service.ts:207
|
||||||||
Saves a work item.
Parameters :
Returns :
Observable<WorkItem>
The updated WorkItem |
startProcess | ||||||||||||||||
startProcess(executableProcessId: string, data: any, contents: literal type[])
|
||||||||||||||||
Defined in src/lib/service/bpm/bpm.service.ts:269
|
||||||||||||||||
Starts an executable process.
Parameters :
Returns :
Observable<any>
|
unlockWorkItem | ||||||||
unlockWorkItem(item: WorkItem)
|
||||||||
Defined in src/lib/service/bpm/bpm.service.ts:257
|
||||||||
Releases the lock for a WorkItem.
Parameters :
Returns :
Observable<WorkItem>
The updated WorkItem |
hasMainExecutableProcesses |
hasMainExecutableProcesses:
|
Type : boolean
|
Defined in src/lib/service/bpm/bpm.service.ts:30
|
processItems$ |
processItems$:
|
Type : Observable<Process[]>
|
Default value : this.processItemsSource.asObservable()
|
Defined in src/lib/service/bpm/bpm.service.ts:37
|
Long term observable emitting the current processes |
BpmService
handles interaction related to BPM tasks.
import {forkJoin as observableForkJoin, of as observableOf, Observable, ReplaySubject, throwError as observableThrowError} from 'rxjs';
import {mergeMap, tap, map} from 'rxjs/operators';
import {Injectable} from '@angular/core';
import {Utils} from '../../util/utils';
import {BackendService} from '../backend/backend.service';
import {WorkItemHistoryEntry} from '../../model/work-item-history.model';
import {DmsObject} from '../../model/dms-object.model';
import {InboxService} from '../inbox/inbox.service';
import {EventService} from '../events/event.service';
import {CapabilitiesService} from '../capabilities/capabilities.service';
import {ExecutableProcess, FileEntry, Process, WorkItem, WorkItemAction} from '../../model/bpm.model';
import {Clipboard} from '../clipboard/clipboard.interface';
import {ClipboardAction} from '../clipboard/clipboard-action.enum';
import {ProcessItem} from '../../model/process-item.model';
/**
* `BpmService` handles interaction related to BPM tasks.
*
* The main parts provided and used by this service are Processes and WorkItems.
* Processes are defined on the backend side. They describe a set of tasks that will be executed by the process.
* Tasks that require user interaction are referred to as WorkItems.
*
* Processes can be related to a special object type, but they don't have to. In addition to that they can refer
* to dms objects.
*/
@Injectable({
providedIn: 'root'
})
export class BpmService {
hasMainExecutableProcesses: boolean;
private executableProcesses: ExecutableProcess[];
private processItems: Process[];
private processItemsSource = new ReplaySubject<Process[]>(1);
/**
* Long term observable emitting the current processes
*/
processItems$: Observable<Process[]> = this.processItemsSource.asObservable();
constructor(private capabilities: CapabilitiesService,
private backend: BackendService,
private eventService: EventService,
private inboxService: InboxService) {
}
/**
* Retrieve all processes of the current user.
*
* @param size Maximum number of processes to be fetched
* @returns List of Processes
*/
getProcesses(size: number = 1000): Observable<Process[]> {
return this.backend
.getJson(`/process/user?size=${size}`, this.backend.getBpmBase())
.pipe(
map(response => response.content.map(item => new Process(item))),
tap((processes: Process[]) => {
this.processItems = processes;
this.processItemsSource.next(this.processItems);
})
);
}
/**
* Getter for the executable Processes. If types are provided, you'll get
* only the processes that are executable for all of them
* @param types List of dms object types to fetch executable processes for
* @param useCached If the cached data should be returned rather than requesting again
* @param additionalData If the additional form data should be also included
* @param modelid The process model ID to only return the data for one process
* @returns List of executable processes
*/
getExecutableProcesses(types?: string[], useCached?: boolean, additionalData?: boolean, modelid?: string, global?: boolean): Observable<ExecutableProcess[]> {
if (this.capabilities.hasCapability('bpm')) {
return (!!this.executableProcesses && useCached) ? observableOf(this.executableProcesses) : this.fetchExecutableProcesses(types, additionalData, modelid, global);
} else {
return observableOf([]);
}
}
initExecutableProcesses(): Observable<any> {
let uri = '/bpm/process/executable';
return this.backend.get(uri).pipe(tap(res => this.hasMainExecutableProcesses = res?.length));
}
/**
* Gets executable Processes for a given set of dms object.You'll get
* only the processes that are executable for all of them.
* @param dmsObjects List of dms objects to fetch executable processes for
* @returns List of executable processes
*/
getExecutableProcessesForDmsObjects(dmsObjects: DmsObject[]): Observable<ExecutableProcess[]> {
return this.getExecutableProcesses(dmsObjects.map(o => o.typeName), false, true);
}
getProcessData(id: string): Observable<ProcessItem[]> {
let uri = Utils.buildUri(`/processes?objectid=${id}&page=0&size=20`, {});
return this.backend.getJson(uri, this.backend.getBpmBase()).pipe(
map(res => res.content.map(i => {
return {
endtime: i.endtime,
iconid: i.iconid,
id: i.id,
modelDisplayName: i.modelDisplayName,
modelid: i.modelid,
starttime: i.starttime,
modelname: i.modelname,
name: i.name,
parentProcessId: i.parentProcessId,
processeditor: i.processeditor,
state: i.state,
subject: i.subject
};
}))
);
}
/**
* Fetches executable Processes from the backend.
* @param types List of dms object types to fetch executable processes for
* @param additionalData If the additional form data should be also included
* @param modelid The process model ID to only return the data for one process
* @returns List of executable processes
*/
private fetchExecutableProcesses(types?: string[], additionalData?: boolean, modelid?: string, global?: boolean): Observable<ExecutableProcess[]> {
let uri = '/bpm/process/executable';
if (additionalData) {
uri += '?form=true&fields=true';
}
if (types) {
uri += (additionalData ? '&' : '?') + `type=${types.join(',')}`;
}
if (modelid) {
uri += (additionalData || types ? '&' : '?') + `modelid=${modelid}`;
}
return this.backend.get(uri).pipe(
map(res => res as ExecutableProcess[]),
tap(res => {
// Extend existing processes with additional data, instead of overwriting all processes
if (global) {
if (additionalData) {
if (!this.executableProcesses) {
this.executableProcesses = [];
}
res.forEach(proc => {
const existingProcIndex = this.executableProcesses.findIndex(item => item.id === proc.id);
if (existingProcIndex === -1) {
this.executableProcesses.push(proc);
} else {
this.executableProcesses[existingProcIndex] = proc;
}
});
} else {
this.executableProcesses = res;
}
}
}));
}
/**
* Getter for a processes file. The file of a process contains
* dms objects attached to the process.
* @param processId ID of the process to fetch attached objects for
*/
getProcessFile(processId: string): Observable<FileEntry[]> {
return this.backend
.getJson(`/process/${processId}/file`, this.backend.getBpmBase()).pipe(
map(res => res.content.map(i => {
return {
id: i.elementid,
title: i.title,
description: i.description ? i.description : '',
iconid: i.iconid,
creator: i.creator,
addtime: i.addtime,
type: i.type
};
}))
);
}
/**
* Retrieves a work item.
* @param processId ID of the parent process
* @param itemId ID of the work item itself
* @param options Options to be added to the backend call
* @returns a WorkItem
*/
getWorkItem(processId: string, itemId: string, options?: any): Observable<WorkItem> {
const params = options ? options : {form: true, fields: true};
const tasks = [
this.backend.getJson(Utils.buildUri(`/bpm/process/${processId}/activity/${itemId}/inboxitem`, params)),
this.getProcessFile(processId)
];
return observableForkJoin(tasks).pipe(
map(res => {
const wi = new WorkItem(res[0]);
wi.setFile(res[1]);
return wi;
}));
}
/**
* Saves a work item.
* @param item The work item to be saved
* @returns The updated WorkItem
*/
saveWorkItem(item: WorkItem): Observable<WorkItem> {
const {id, processId, file, data} = item;
const payload = {contents: file, data};
const params = {keeplock: true, isautolock: false};
return this.backend
.post(Utils.buildUri(`/bpm/process/${processId}/activity/${id}/inboxitem/save`, params), payload)
.pipe(
mergeMap(() => this.getWorkItem(processId, id))
);
}
/**
* Forwards a work item. If a WorkItem provides different actions (@link WorkItemAction)
* you can provide the selected action too.
* @param item The work item to be forwarded
* @param action Action used for forwarding
*/
forwardWorkItem(item: WorkItem, action?: WorkItemAction): Observable<any> {
const params = {keeplock: false, isautolock: false};
const payload = {
action: action,
contents: item.file,
data: item.data
};
return this.backend
.post(Utils.buildUri(`/bpm/process/${item.processId}/activity/${item.id}/inboxitem/save`, params), payload)
.pipe(
tap(() => this.inboxService.updateInboxItems(item.id))
);
}
/**
* Locks a WorkItem for the current user (personalization), meaning that the
* current user is now in charge of fulfilling the WorkItem task.
* @param item The WorkItem to be locked
* @returns The updated WorkItem
*/
lockWorkItem(item: WorkItem): Observable<WorkItem> {
return this.backend.put(`/bpm/process/${item.processId}/activity/${item.id}/inboxitem/lock`)
.pipe(
mergeMap(() => this.getWorkItem(item.processId, item.id))
);
}
/**
* Releases the lock for a WorkItem.
* @param item The work item to be unlocked
* @returns The updated WorkItem
*/
unlockWorkItem(item: WorkItem): Observable<WorkItem> {
return this.backend.del(`/bpm/process/${item.processId}/activity/${item.id}/inboxitem/lock`).pipe(
mergeMap(() => this.getWorkItem(item.processId, item.id))
);
}
/**
* Starts an executable process.
* @param executableProcessId ID of the executable Process to be started
* @param data Data to be passed to the process (simple object of key/value pairs)
* @param contents Objects to be attached to the process (process.file).
*/
startProcess(executableProcessId: string, data: any, contents: {id: string, type: string}[]): Observable<any> {
// Create updatedData by transforming 'data' to extract value if the property has 'actualOperator'
const updatedData = {
...data,
...Object.fromEntries(
Object.entries(data).map(([key, value]) => {
const isObjectWithActualOperator = value && typeof value === 'object' && 'actualOperator' in value;
const hasArrayValue = isObjectWithActualOperator && Array.isArray((value as any).value) && (value as any).value.length > 0;
return hasArrayValue ? [key, (value as any).value[0]] : [key, value];
})
)
};
return this.backend.post(`/bpm/process/?modelid=${executableProcessId}`, {
data: updatedData,
contents: contents
});
}
/**
* Returns the history for a process. Which entries are returned depends on the
* permissions of the current user.
* @param processId The ID of the process to fetch history for
* @returns Observable<WorkItemHistoryEntry[]>
*/
getProcessHistory(processId: string): Observable<WorkItemHistoryEntry[]> {
return this.backend
.getJson(`/bpm/process/${processId}/history`)
.pipe(map(res => res && res.length ? res.map(item => new WorkItemHistoryEntry(item)) : []));
}
/**
* Removes a content from the work items file.
* @param processId The ID of the process to remove the item from
* @param workItemId The ID of the work item containing the file element to be removed
* @param workItemContentId The the ID of the file element to be removed
*/
removeFileElement(processId: string, workItemId: string, workItemContentId: string): Observable<any> {
return this.backend
.del(`/process/${processId}/file/${workItemContentId}?activityid=${workItemId}`, this.backend.getBpmBase());
}
/**
* Add contents to a work items file.
* @param processId The ID of the process
* @param workItemId The ID of the activity
* @param elements The Elements to be added
* @returns The updated WorkItem
*/
addFileElements(processId: string, workItemId: string, elements: DmsObject[]): Observable<WorkItem> {
const tasks = [];
elements.forEach((e) => {
tasks.push(this.backend.post(
`/process/${processId}/file/${e.id}?type=${e.type.name}&activityid=${workItemId}`,
{}, this.backend.getBpmBase()));
});
return observableForkJoin(tasks)
.pipe(
mergeMap(() => this.getWorkItem(processId, workItemId))
);
}
/**
* Fetch all available bpm projects including all of their model data
* @returns list of all the projects including the models
*/
fetchProcessModels(): Observable<[]> {
const uri = Utils.buildUri(`/bpm/management/project?includeModels=true`, {});
return this.backend.get(uri);
}
/**
* Add a objects from the clipboard to a WorkItem.
* @param workItem The workItem to add the objects to
* @param clipboard Clipboard object holding user selected objects
* @returns The updated WorkItem
*/
addFileElementsFromClipboard(workItem: WorkItem, clipboard: Clipboard): Observable<WorkItem> {
if ((workItem && workItem.fileEntryPermissions.add) && clipboard && clipboard.elements.length && clipboard.action === ClipboardAction.COPY) {
let contents: DmsObject[];
if (workItem.file.length) {
// only add items that are not already part of the attachments
const attachmentIds = workItem.file.map(e => e.id);
contents = clipboard.elements.filter(e => attachmentIds.indexOf(e.id) === -1);
} else {
contents = clipboard.elements;
}
return this.addFileElements(workItem.processId, workItem.id, contents);
} else {
return observableThrowError('error');
}
}
}