Jmix View
When you need a process form with a complex layout and behavior, you can use an existing Jmix UI view instead of input dialog forms. A view controller should be annotated with the @ProcessForm
annotation to be used as a process form.
The @ProcessForm
annotation indicates that the view must appear in the process forms combo box in the modeler.
Process Variables
@ProcessVariable
annotation can be placed on injected UI components or regular class fields.
It indicates that the value of the process variable will be written to this field when the process form is opened. In case of the UI component, the value of the process variable will be set to the UI component.
@ProcessVariable
private Date date;
@ViewComponent
@ProcessVariable(name = "order")
private EntityPicker<Order> orderEntityPicker;
If you configure the ProcessFormContext with the saveInjectedProcessVariables()
method, then the values of annotated fields will be saved as process variables when the process is started or the user task is completed.
@ProcessVariable
annotation has an optional name
attribute. The value of this attribute is the process variable name. If the name attribute is missing, then the field name is used as the process variable name.
ProcessFormContext
The ProcessFormContext
object contains information about a process’s definition to be started (when the form is used for starting the process) or a user task to be completed.
You can use ProcessFormContext
if the process form is opened from the Start process and My tasks views. If you need to open the process form with the injected ProcessFormContext
programmatically, use the ProcessFormViews bean.
The ProcessFormContext
object also contains methods for starting the process and task completion.
An example of how to start a process:
@ProcessVariable
private Date date;
@ViewComponent
@ProcessVariable(name = "order")
private EntityPicker<Order> orderEntityPicker;
@Autowired
private ProcessFormContext processFormContext;
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(ClickEvent<JmixButton> event) {
processFormContext.processStarting() (1)
.withBusinessKey("order-1") (2)
.addProcessVariable("date", date)
.addProcessVariable("order", orderEntityPicker.getValue()) (3)
.start(); (4)
closeWithDefaultAction(); (5)
}
1 | Creates a ProcessStarting instance. |
2 | Sets a business key to the process instance. |
3 | Adds a process variable. |
4 | Starts the actual process. |
5 | Closes the opened window. |
An example of how to complete the user task:
@Autowired
private ProcessFormContext processFormContext;
@Subscribe("rejectBtn")
protected void onRejectBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion() (1)
.withOutcome("reject") (2)
.saveInjectedProcessVariables() (3)
.complete(); (4)
closeWithDefaultAction(); (5)
}
1 | Creates a TaskCompletion instance. |
2 | Sets a task outcome. |
3 | Indicates that values of class fields annotated with the @ProcessVariables should be collected and saved as process variables. |
4 | Completes the actual task. |
5 | Closes the opened window. |
Declare Task Outcomes
In the modeler, for the sequence flow element, you can define a condition by selecting a user task and its outcome from the drop-down list. To fill this list for a user task that uses a Jmix view process form, you can declare a list of possible outcomes in the form controller. Use the outcomes
attribute of the @ProcessForm
annotation for that.
@ProcessForm(
outcomes = { (1)
@Outcome(id = "approve"),
@Outcome(id = "reject")
}
)
public class OrderApprovalTaskForm extends StandardView {
Process Form Parameters
Jmix view process forms can accept external parameters defined in the modeler. The form parameters used by the form are defined in the params
attribute of the @ProcessForm
annotation:
@ProcessForm(
params = {
@Param(name = "variableName"),
@Param(name = "entityPickerCaption")
}
)
These parameters are read by the modeler, and you can see them after selecting the view.
You can edit the parameters and provide a direct param value or use one of the existing process variables as a parameter value.
Inside the process form controller, use the @ProcessFormParam
annotation on class fields to get parameter values.
@ProcessFormParam
private String variableName;
@ProcessFormParam
private String entityPickerCaption;
Another way to get a full list of process form parameters is to get them from the ProcessFormContext
object:
List<FormParam> formParams = processFormContext.getFormData().getFormParams();
As the @ProcessVariable
annotation, the @ProcessFormParam
supports an optional name
attribute. If the attribute is not defined, then a field name is used as a parameter name.
See an example of a process form with parameters.
Output Variables
When you model the process, it may be useful to know which variables are set by the Jmix view process form in order to reuse them later in the process model. A way to achieve this is to use the outputVariabes
attribute of the @ProcessForm
annotation.
@ProcessForm(
outputVariables = {
@OutputVariable(name = "order", type = Order.class),
@OutputVariable(name = "comment", type = String.class)
}
)
Often there are cases when a process variable is set only when the task is completed using a particular outcome. To declare this, place the outputVariables
annotation attribute to the @Outcome
annotation.
@ProcessForm(
outcomes = {
@Outcome(
id = "approve",
outputVariables = {
@OutputVariable(name = "nextActor", type = User.class) (1)
}
),
@Outcome(
id = "reject",
outputVariables = {
@OutputVariable(name = "rejectionReason", type = String.class) (2)
}
)
},
outputVariables = {
@OutputVariable(name = "comment", type = String.class) (3)
}
)
1 | The nextActor variable can be set when the task is completed with the approve outcome. |
2 | The rejectionReason variable can be set when the task is completed with the reject outcome. |
3 | The comment variable can be set in any case. |
Output variables information is displayed in the corresponding section in the properties panel when you select the process form.
Restrict Process Form Usage
By default, all process forms views are available within any process model. If you want to use some view in particular processes only, then you should specify processes keys in the allowedProcessKeys
attribute of the @ProcessForm
annotation.
@ProcessForm(allowedProcessKeys = {"process-1", "process-2"})
The form will be available only for process with process-1
and process-2
process ids in the modeler.
Opening Forms Programmatically
You can use the ProcessFormViews
service to create start process forms and task process forms defined in the modeler.
In the example below, the start process form is opened by clicking the button in the browser view.
@Autowired
private RepositoryService repositoryService;
@Autowired
protected ProcessFormViews processFormViews;
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(final ClickEvent<JmixButton> event) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() (1)
.processDefinitionKey("order-process")
.latestVersion()
.singleResult();
processFormViews.openStartProcessForm(processDefinition, this); (2)
}
1 | Gets a process definition with the order-process key. |
2 | Shows the start process form with the received process definition. |
The start process form can look like an example in the ProcessFormContext section.
To create a task form, use the openTaskProcessForm
method:
@Autowired
private TaskService taskService;
@Autowired
private ProcessFormViews processFormViews;
@Subscribe("openTaskBtn")
public void onOpenTaskBtnClick(ClickEvent<JmixButton> event) {
Task task = taskService.createTaskQuery()
.processDefinitionKey("approve-order-process")
.taskAssignee("admin")
.active()
.orderByTaskCreateTime()
.list()
.get(0);
processFormViews.openTaskProcessForm(task, this);
}
The task process form can look like an example in the ProcessFormContext section.
Examples
Start Process Form
Let’s look at the example of the process form that is used as a start form. The form displays two fields:
-
a text field to enter the order number.
-
an entityPicker to select the manager. The manager can be the next process actor.
View XML descriptor:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://com.company.bpmex1.view.forms/startProcessForm.title">
<layout>
<formLayout>
<textField id="orderNumber"
label="msg://com.company.bpmex1.view.forms/orderNumber"
datatype="string"/>
<entityPicker id="managerEntityPicker"
metaClass="User"
label="msg://managerEntityPicker.caption">
<actions>
<action id="lookup" type="entity_lookup"/>
<action id="clear" type="entity_clear"/>
</actions>
</entityPicker>
</formLayout>
<hbox id="actionsPanel" spacing="true">
<button id="startProcessBtn"
icon="CHECK"
text="msg://com.company.bpmex1.view.forms/startProcessBtn.text"/>
</hbox>
</layout>
</view>
View controller:
@ViewController("OrderApprovalStartForm")
@ViewDescriptor("order-approval-start-form.xml")
@ProcessForm (1)
public class OrderApprovalStartForm extends StandardView {
@ViewComponent
@ProcessVariable (2)
private TypedTextField<String> orderNumber;
@ViewComponent
@ProcessVariable(name = "manager") (3)
private EntityPicker<User> managerEntityPicker;
@Autowired
private ProcessFormContext processFormContext; (4)
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(ClickEvent<JmixButton> event) {
processFormContext.processStarting()
.withBusinessKey(orderNumber.getValue()) (5)
.saveInjectedProcessVariables() (6)
.start();
closeWithDefaultAction();
}
}
1 | The @ProcessForm annotation indicates that this view is a process form and the view will be available in the modeler. |
2 | We declare that the injected orderNumber UI component is a process variable. Since we develop a start process form, the variable has no value yet, but the annotation will be used on process start. |
3 | The same as 2, but here the manager process variable name differs from the managerEntityPicker field name. |
4 | ProcessFormContext is the object that we use to start the process. |
5 | When we start the process, we can pass an optional process instance business key. We use the orderNumber here. |
6 | The saveInjectedProcessVariables() indicates that values of the fields annotated with the @ProcessVariables should be saved as process variables on process start. |
Instead of using saveInjectedProcessVariables()
method you can explicitly set process variables:
@Subscribe("startProcessBtn")
public void onStartProcessBtnClick(ClickEvent<JmixButton> event) {
processFormContext.processStarting()
.withBusinessKey(orderNumber.getValue())
.addProcessVariable("orderNumber", orderNumber.getValue())
.addProcessVariable("manager",managerEntityPicker.getValue())
.start();
closeWithDefaultAction();
}
Task Process Form
Let’s look at the example of the task process form that displays two fields:
-
The first one will display a value of the existing process variable -
orderNumber
. -
The second field will be used for the new process variable -
comment
.
Approve and Reject buttons complete the user task with the corresponding outcome.
View XML descriptor:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://orderApprovalTaskForm.title">
<layout>
<formLayout>
<textField id="orderNumber" readOnly="true"
label="msg://orderNumber"/>
<textField id="commentField" label="msg://comment"/>
</formLayout>
<hbox id="actionsPanel" spacing="true">
<button id="approveBtn" icon="CHECK" text="msg://approveBtn.text"/>
<button id="rejectBtn" icon="BAN" text="msg://rejectBtn.text"/>
</hbox>
</layout>
</view>
View controller:
@ViewController("OrderApprovalTaskForm")
@ViewDescriptor("order-approval-task-form.xml")
@ProcessForm(
outcomes = { (1)
@Outcome(id = "approve"),
@Outcome(id = "reject")
}
)
public class OrderApprovalTaskForm extends StandardView {
@ViewComponent
@ProcessVariable (2)
private TypedTextField<String> orderNumber;
@ViewComponent
@ProcessVariable(name = "comment") (3)
private TypedTextField<String> commentField;
@Autowired
private ProcessFormContext processFormContext;
@Subscribe("approveBtn")
protected void onApproveBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.withOutcome("approve")
.saveInjectedProcessVariables() (4)
.complete();
closeWithDefaultAction();
}
@Subscribe("rejectBtn")
protected void onRejectBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.withOutcome("reject")
.addProcessVariable("comment", commentField.getValue()) (5)
.complete();
closeWithDefaultAction();
}
}
1 | The form defines two possible outcomes that can be used in a sequence flow node condition in the modeler. This information is used by the modeler only. |
2 | The orderNumber variable has been already set on process start. Because of the @ProcessVariable annotation, the value of the orderNumber process variables will be set to the orderNumber text field when the form is displayed. |
3 | The comment variable is not set yet, but the @ProcessVariable annotation will be taken into account when we complete the task in the button click listener. |
4 | Values of all fields annotated with the @ProcessVariable will be saved as process variables on task completion. |
5 | An alternative way to define process variables. Instead of using the saveInjectedProcessVariables() method, you can define process variables directly. |
Process Form with Parameters
Let’s assume that you need a form for the next process actor selection. The form should display EntityPicker
field with users and save the result into a process variable. We want to use the form for selecting different actors at different process steps, so the form should have two parameters:
-
variableName
-
entityPickerCaption
View XML descriptor:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://com.company.bpmex1.view.forms/actorSelectionForm.title">
<layout spacing="true">
<formLayout width="20em">
<entityPicker id="userEntityPicker"
metaClass="User"
property="username">
<actions>
<action id="lookup" type="entity_lookup"/>
<action id="clear" type="entity_clear"/>
</actions>
</entityPicker>
</formLayout>
<hbox spacing="true">
<button id="completeTaskBtn" icon="CHECK" text="msg://completeTask"/>
</hbox>
</layout>
</view>
View controller:
@ProcessForm(
params = {
@Param(name = "variableName"),
@Param(name = "entityPickerCaption")
}
)
public class ActorSelectionForm extends StandardView {
@Autowired
private ProcessFormContext processFormContext;
@ViewComponent
private EntityPicker<String> userEntityPicker;
@ProcessFormParam
private String variableName;
@ProcessFormParam
private String entityPickerCaption;
@Subscribe
private void onBeforeShow(BeforeShowEvent event) {
userEntityPicker.setLabel(entityPickerCaption);
}
@Subscribe("completeTaskBtn")
private void onCompleteTaskBtnClick(ClickEvent<JmixButton> event) {
processFormContext.taskCompletion()
.addProcessVariable(variableName, userEntityPicker.getValue())
.complete();
closeWithDefaultAction();
}
}