Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@
* complete the current BPM user task: the Inbox/Process perspective opens the form with
* {@code ?taskId=&processInstanceId=}, and the handler POSTs {@code COMPLETE} to
* {@code /services/bpm/bpm-processes/tasks/<taskId>} with the action name and the form model as
* process variables (so a downstream gateway can branch on the action). Forms opened outside a task
* process variables (so a downstream gateway can branch on the action). On success the handler
* closes its host via both {@code DialogHub.closeWindow()} and {@code window.close()} - the former
* closes the dialog when the form is opened from an entity view, the latter a standalone
* (script-opened) window; each is a harmless no-op where it does not apply, including the Inbox's
* inline iframe (which clears its own pane on its refresh cycle). Forms opened outside a task
* report the missing {@code taskId} instead of failing silently. Business logic beyond completing
* the task belongs in a hand-written form override under {@code custom/}.
*
Expand Down Expand Up @@ -146,6 +150,7 @@ private static String buildCode(FormIntent form) {
const __taskParams = new URLSearchParams(window.location.search);
const __taskId = __taskParams.get('taskId');
const __notifications = new NotificationHub();
const __dialogs = new DialogHub();

function __completeTask(action) {
if (!__taskId) {
Expand All @@ -157,6 +162,7 @@ function __completeTask(action) {
data: Object.assign({ action: action }, $scope.model || {})
}).then(() => {
__notifications.show({ type: 'positive', title: 'Task submitted', description: 'The task was completed (' + action + ').' });
__dialogs.closeWindow();
window.close();
}).catch((error) => {
const message = error && error.data && error.data.message ? error.data.message : 'Unknown error';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2010-2026 Eclipse Dirigible contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-FileCopyrightText: Eclipse Dirigible contributors
* SPDX-License-Identifier: EPL-2.0
*/
/**
* Shared support for surfacing a record's BPM user tasks as in-context actions on generated entity
* views. A process-aware entity carries a system-managed ProcessId (the started process-instance id,
* written back by the intent process trigger); the current user's actionable inbox tasks are fetched
* once and bucketed by processInstanceId, so any view - list, manage, or a master-detail pane - can
* surface the tasks for a given record regardless of its layout.
*
* Usage in a generated view: depend on the 'ProcessTasks' module and drop
* <entity-process-tasks entity="<record>"></entity-process-tasks> next to the record's actions.
*/
angular.module('ProcessTasks', ['platformLocale'])
.factory('ProcessTasks', ['$http', 'LocaleService', function ($http, LocaleService) {
const Dialogs = new DialogHub();
let byProcessId = {};
let loadPromise = null;

const bucket = (responses) => {
const map = {};
const seen = new Set();
const collect = (tasks, mine) => (tasks || []).forEach((task) => {
if (!task.processInstanceId || seen.has(task.id)) return;
seen.add(task.id);
task.mine = mine;
(map[task.processInstanceId] = map[task.processInstanceId] || []).push(task);
});
collect(responses[0].data, true);
collect(responses[1].data, false);
return map;
};

const load = () => {
loadPromise = Promise.all([
$http.get('/services/inbox/tasks?type=assignee', { params: { limit: 100 } }),
$http.get('/services/inbox/tasks?type=groups', { params: { limit: 100 } })
]).then((responses) => {
byProcessId = bucket(responses);
return byProcessId;
}, (error) => {
byProcessId = {};
console.error('ProcessTasks: unable to load inbox tasks', error);
return byProcessId;
});
return loadPromise;
};

const openForm = (task) => {
if (!task.formKey) {
Dialogs.showAlert({
title: task.name,
message: LocaleService.t('dashboard.processTasks.noForm', {}, 'This task has no form to display.'),
type: AlertTypes.Information
});
return;
}
const separator = task.formKey.indexOf('?') >= 0 ? '&' : '?';
const formUrl = task.formKey + separator + 'taskId=' + encodeURIComponent(task.id) + '&processInstanceId=' + encodeURIComponent(task.processInstanceId);
// The generated task form completes the task and closes this window itself (DialogHub.closeWindow);
// we just re-fetch when it closes so the originating view's badge drops the completed task.
const closeTopic = 'dashboard.processTasks.window.' + task.id;
const closeListener = Dialogs.addMessageListener({
topic: closeTopic,
handler: () => {
Dialogs.removeMessageListener(closeListener);
load();
}
});
Dialogs.showWindow({
hasHeader: true,
title: task.name,
path: formUrl,
closeButton: true,
callbackTopic: closeTopic
});
};

return {
/** Force a re-fetch of the current user's tasks (call after a list reload / record change). */
refresh: () => load(),
/** Fetch once if not already loaded; subsequent calls reuse the in-flight / cached result. */
ensureLoaded: () => loadPromise || load(),
/** The cached actionable tasks for a record, matched by entity.ProcessId === task.processInstanceId. */
getTasks: (entity) => (entity && entity.ProcessId && byProcessId[entity.ProcessId]) || [],
/** Open a task's form; a candidate (not-yet-assigned) task is claimed for the user first. */
openTask: (task) => {
if (task.mine) {
openForm(task);
return;
}
$http.post('/services/inbox/tasks/' + task.id, { action: 'CLAIM' }).then(() => {
task.mine = true;
openForm(task);
load();
}, (error) => {
const message = error.data ? error.data.message : '';
Dialogs.showAlert({
title: task.name,
message: LocaleService.t('dashboard.processTasks.unableToClaim', { message: message }, `Unable to claim task: '${message}'`),
type: AlertTypes.Error
});
console.error('ProcessTasks: unable to claim task', error);
});
}
};
}])
.directive('entityProcessTasks', ['ProcessTasks', 'LocaleService', function (ProcessTasks, LocaleService) {
return {
restrict: 'E',
scope: { entity: '<' },
template: `<bk-popover ng-if="tasks().length">
<bk-popover-control>
<bk-button compact="true" glyph="sap-icon--inbox" state="transparent" label="{{tasks().length}}" aria-label="{{ariaLabel}}"></bk-button>
</bk-popover-control>
<bk-popover-body align="bottom-right">
<bk-menu no-backdrop="true" no-shadow="true">
<bk-menu-item ng-repeat="task in tasks() track by task.id" title="{{task.name}}" ng-click="openTask(task)"></bk-menu-item>
</bk-menu>
</bk-popover-body>
</bk-popover>`,
link: (scope) => {
scope.ariaLabel = LocaleService.t('dashboard.processTasks.pending', {}, 'Pending tasks');
scope.tasks = () => ProcessTasks.getTasks(scope.entity);
scope.openTask = (task) => ProcessTasks.openTask(task);
ProcessTasks.ensureLoaded().then(() => scope.$applyAsync());
}
};
}]);
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#set($dollar = '$')
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'])
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'#if($hasProcess), 'ProcessTasks'#end])
.config(['EntityServiceProvider', (EntityServiceProvider) => {
EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller';
}])
.controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService) => {
.controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService#if($hasProcess), ProcessTasks#end) => {
const Dialogs = new DialogHub();
$scope.dataPage = 1;
$scope.dataCount = 0;
Expand Down Expand Up @@ -120,6 +120,9 @@ angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntitySer

#end
$scope.data = response.data;
#if($hasProcess)
ProcessTasks.refresh();
#end
}, (error) => {
const message = error.data ? error.data.message : '';
Dialogs.showAlert({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<script type="text/javascript" src="view.js"></script>
<meta name="platform-links" category="ng-view">
<script type="text/javascript" src="/services/web/dashboard/services/entity.js"></script>
#if($hasProcess)
<script type="text/javascript" src="/services/web/dashboard/services/process-tasks.js"></script>
#end
<script type="text/javascript" src="controller.js"></script>
</head>

Expand Down Expand Up @@ -91,6 +94,9 @@
#end
#end
<td bk-table-cell fit-content="true">
#if($hasProcess)
<entity-process-tasks entity="next"></entity-process-tasks>
#end
<bk-popover>
<bk-popover-control>
<bk-button compact="true" glyph="sap-icon--overflow" state="transparent" aria-label="{{'$projectName:${tprefix}.aria.tableRowMenuBtn' | t}}" ng-click="setTristate()"></bk-button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#set($dollar = '$')
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'])
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'#if($hasProcess), 'ProcessTasks'#end])
.config(['EntityServiceProvider', (EntityServiceProvider) => {
EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller';
}])
.controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates) => {
.controller('PageController', (${dollar}scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates#if($hasProcess), ProcessTasks#end) => {
const Dialogs = new DialogHub();
let translated = {
yes: 'Yes',
Expand Down Expand Up @@ -140,6 +140,9 @@ angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntitySer

#end
$scope.data = response.data;
#if($hasProcess)
ProcessTasks.refresh();
#end
}, (error) => {
const message = error.data ? error.data.message : '';
Dialogs.showAlert({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<script type="text/javascript" src="view.js"></script>
<meta name="platform-links" category="ng-view">
<script type="text/javascript" src="/services/web/dashboard/services/entity.js"></script>
#if($hasProcess)
<script type="text/javascript" src="/services/web/dashboard/services/process-tasks.js"></script>
#end
<script type="text/javascript" src="controller.js"></script>
</head>

Expand Down Expand Up @@ -92,6 +95,9 @@
#end
#end
<td bk-table-cell fit-content="true">
#if($hasProcess)
<entity-process-tasks entity="next"></entity-process-tasks>
#end
<bk-popover>
<bk-popover-control>
<bk-button compact="true" glyph="sap-icon--overflow" state="transparent" aria-label="{{'$projectName:${tprefix}.aria.tableRowMenuBtn' | t}}" ng-click="setTristate()"></bk-button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#set($dollar = '$')
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'])
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'#if($hasProcess), 'ProcessTasks'#end])
.config(['EntityServiceProvider', (EntityServiceProvider) => {
EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller';
}])
.controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService) => {
.controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService#if($hasProcess), ProcessTasks#end) => {
const Dialogs = new DialogHub();
//-----------------Custom Actions-------------------//
Extensions.getWindows(['${projectName}-custom-action']).then((response) => {
Expand Down Expand Up @@ -136,6 +136,9 @@ angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntitySer

#end
$scope.data = response.data;
#if($hasProcess)
ProcessTasks.refresh();
#end
}, (error) => {
const message = error.data ? error.data.message : '';
Dialogs.showAlert({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<script type="text/javascript" src="view.js"></script>
<meta name="platform-links" category="ng-view">
<script type="text/javascript" src="/services/web/dashboard/services/entity.js"></script>
#if($hasProcess)
<script type="text/javascript" src="/services/web/dashboard/services/process-tasks.js"></script>
#end
<script type="text/javascript" src="controller.js"></script>
</head>

Expand Down Expand Up @@ -94,6 +97,9 @@
#end
#end
<td bk-table-cell fit-content="true">
#if($hasProcess)
<entity-process-tasks entity="next"></entity-process-tasks>
#end
<bk-popover>
<bk-popover-control>
<bk-button compact="true" glyph="sap-icon--overflow" state="transparent" aria-label="{{'$projectName:${tprefix}.aria.tableRowMenuBtn' | t}}" ng-click="setTristate()"></bk-button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#set($dollar = '$')
angular.module('page', ['blimpKit', 'platformView', 'platformLocale']).controller('PageController', ($scope, Extensions, LocaleService) => {
angular.module('page', ['blimpKit', 'platformView', 'platformLocale'#if($hasProcess), 'ProcessTasks'#end]).controller('PageController', ($scope, Extensions, LocaleService) => {
const Dialogs = new DialogHub();
$scope.entity = {};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<title config-title></title>
<script type="text/javascript" src="view.js"></script>
<meta name="platform-links" category="ng-view">
#if($hasProcess)
<script type="text/javascript" src="/services/web/dashboard/services/process-tasks.js"></script>
#end
<script type="text/javascript" src="controller.js"></script>
</head>

Expand Down Expand Up @@ -235,6 +238,15 @@
</bk-fieldset>
</bk-scrollbar>

#if($hasProcess)
<bk-bar bar-design="footer" compact="true" ng-show="entity.${primaryKeysString}">
<bk-bar-right>
<bk-bar-element>
<entity-process-tasks entity="entity"></entity-process-tasks>
</bk-bar-element>
</bk-bar-right>
</bk-bar>
#end
<bk-bar bar-design="footer" compact="true" ng-show="entityActions.length && entity.${primaryKeysString}">
<bk-bar-right>
<bk-bar-element ng-repeat="action in entityActions track by $index">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#set($dollar = '$')
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'])
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'#if($hasProcess), 'ProcessTasks'#end])
.config(['EntityServiceProvider', (EntityServiceProvider) => {
EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller';
}])
.controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates) => {
.controller('PageController', ($scope,#if($hasDropdowns) ${dollar}http,#end EntityService, Extensions, LocaleService, ButtonStates#if($hasProcess), ProcessTasks#end) => {
const Dialogs = new DialogHub();
let translated = {
yes: 'Yes',
Expand Down Expand Up @@ -157,6 +157,9 @@ angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntitySer

#end
$scope.data = response.data;
#if($hasProcess)
ProcessTasks.refresh();
#end
}, (error) => {
const message = error.data ? error.data.message : '';
Dialogs.showAlert({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<script type="text/javascript" src="view.js"></script>
<meta name="platform-links" category="ng-view">
<script type="text/javascript" src="/services/web/dashboard/services/entity.js"></script>
#if($hasProcess)
<script type="text/javascript" src="/services/web/dashboard/services/process-tasks.js"></script>
#end
<script type="text/javascript" src="controller.js"></script>
</head>

Expand Down Expand Up @@ -94,6 +97,9 @@
#end
#end
<td bk-table-cell fit-content="true">
#if($hasProcess)
<entity-process-tasks entity="next"></entity-process-tasks>
#end
<bk-popover>
<bk-popover-control>
<bk-button compact="true" glyph="sap-icon--overflow" state="transparent" aria-label="{{'$projectName:${tprefix}.aria.tableRowMenuBtn' | t}}" ng-click="setTristate()"></bk-button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#set($dollar = '$')
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'])
angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService'#if($hasProcess), 'ProcessTasks'#end])
.config(["EntityServiceProvider", (EntityServiceProvider) => {
EntityServiceProvider.baseUrl = '/services/java/${projectName}/gen/${javaGenFolderName}/api/${javaPerspectiveName}/${name}Controller';
}])
Expand Down
Loading
Loading