1. Intro
This step-by-step tutorial will help new edoras one modelers get started with defining Apps for the edoras one platform.
It’s a good idea to have read the basic edoras one intro (general guide) as well as the edoras one user guide, both of which can be found here: http://documentation.edorasware.com
1.1. What you will learn
By following this tutorial, step by step, you will learn how to create your own App, including the following:
-
Creating case models
-
Designing forms
-
Designing processes
-
Creating ad-hoc task models
-
Creating email templates
-
Creating documents models
-
Creating queries
-
Customizing dashboards
1.2. Tutorial App
For this tutorial we will use the scenario of building an App to handle travel requests. A person who needs to travel will start a new travel request, and a travel agent will organize all the necessary bookings for the trip.
The request process will be built step by step, adding approvers to the process, modeling a feedback-loop between travel agent and requestor and by adding mail tasks to send out information once the travel has been organized.
Everything around the travel request is modeled within a case, so we can attach any necessary information (such as reservation information or vouchers) directly to the case, as well as having an overview of everything going on while managing the travel request.
2. Basic Travel Request Case and Form
In this chapter you will create the Tutorial App
with a new form and case model,
deploy it and test the new case model within the user dashboard.
2.1. Creating a new App
In order to get started, go to the modeler dashboard
and hit c
or click the Create
button in the menu and choose Create App
.
Type Tutorial App
as the name for the App.
Select English
as the primary language for the App.
Select any other languages you want as secondary languages.
As an App can be modeled in several languages, you specify a main (primary) language for the App,
which will act as the default language, if not all elements are translated.
You will be able to design forms and processes with all languages you selected (primary will be default).
Now click Create and navigate to the newly created App by clicking on the link in the green success message you see on the top of the screen.
|
2.2. Creating a form to start the travel request
Let’s create a first form by typing again c
(shortcut) or clicking the Create
button in the menu.
Now let’s choose Create Form Model
and make sure the Tutorial App
is selected as the parent App (meaning the new form model will be created inside that App).
Type Travel Request Form
as the name for the new form model and click Create and design
in order to create the model and directly go to the form designer.
2.2.1. Getting familiar with the basics of the form designer
The form designer consists of three parts: on the left you can find the shape palette, the main canvas for the form design in the middle and on the right-hand side you can find the attributes of the currently selected widget (component) on the canvas.
You can add a new widget to the canvas by simply dragging & dropping it from the shape palette to the canvas. During the drag & drop you will get feedback by the responsive layout manager on where the widget can be dropped.
The layout is responsive, with twelve slots you can use to arrange your widgets. By using the handles on the left or right side of a widget, you can define the span of the widget from one up to twelve slots.
The shape palette has several sections to choose from. Use the predefined widgets if you don’t want to worry about bindings and any other technical issues. The widget section has a wide collection of all the available widgets, which will need configuration through the attributes section.
2.2.2. Add name and description widgets
To start with the design, let’s use two predefined fields: the name and description. These fields are always available and each work item supports them.
Now drag & drop the name and description field from the predefined bindings
section on to the empty form.
Rename the name label to Travel subject
and the description label to Travel notes
.
2.2.3. Add traveling locations
Now let’s add two fields to enter the origin and destination of the travel.
There is no predefined field for location, so let’s use the Text
field from the Components
section.
Name the first one Origin
and the second one Destination
.
By dropping the second field onto the first one, the row will split into two parts with both fields in the same row, each spanning six slots.
Instead of navigating through the shape palette, you can also use the filter functionality to quickly find a specific widget. Click the filter icon in the top right
corner of the Shape palette and type the name of the widget into the search field (e.g. text ).
|
To make the fields mandatory, select a field and click the red star icon. Do this for both Fields.
You can also achieve the same result by clicking the Required
attribute in right side panel.
2.2.4. Getting familiar with the data model behind work items
Before we can define the data bindings for the new fields, let’s have a short look at how data is stored and managed within edoras one.
The basic structure to manage anything within edoras one is called a work item
.
A work item is an object of a particular type (e.g. a case, a task, a process or a document),
its behavior is driven by its type and model (e.g. a process work item is driven by its process model, which in our case is modeled with BPMN 2).
Besides its behavior, every work item is able to store arbitrary data, called variables
.
Variables hold different types of data, such as text, numeric value, a date or a boolean value.
Variables can even hold lists of data or maps or even lists of maps with unlimited nesting.
In order to enter or display the data of work items, its variables can be mapped (bound) to fields.
2.2.5. Define data bindings for the fields
The next step is to set the binding for the newly added fields.
Double-click the field or go to the Value
attribute on the right side.
Bindings tell the form engine where to save and load the data for a particular field.
Let’s save the origin in a variable named travelOrigin
and destination in a variable named travelDestination
, respectively.
Bindings are specified using expressions, which start with a double curly brace {{
and end with a double curly brace }}
.
If we don’t specify any prefix to the variable name, the data is stored and retrieved from the same work item the form is associated with.
2.2.6. Add date pickers for the outward and return trip dates
Now let’s add two new fields to pick the starting and ending date for the travel.
Drag & drop two Date
fields on the form and name them Outward trip date
and Return trip date
, respectively.
Make the fields mandatory and set the bindings to {{outwardTripDate}}
and {{returnTripDate}}
.
2.2.7. Add validation to the date pickers
As we want to make sure there is no date selected in the past, let’s add a validation rule to the date picker.
You can do so by selecting the date field and then clicking on the Minimum date
attribute on the right side under Specific attributes
.
Select a relative date validation by choosing Today + 0 Days
.
For the Return trip date
we also want to add a validation rule. Here we want to ensure that the selected date is not before the Outward trip date
.
To achieve this, we simply add {{outwardTripDate}}
to the Minimum date
attribute of the Return trip date
widget.
Save the form by clicking the Save
icon in the designer menu on the left.
2.3. Create case model
Now switch back to the browser tab where you created the new form (not the form designer)
and click the Create
button once again and select Create case model
.
Fill out the case model form:
-
Set
Travel Request
as the name -
Choose the
Travel Request Form
as both the init form and the work form of the case -
Everything else can be left as it is by default, we will make changes to that later in the tutorial
Click Create
to create the new case model.
2.4. Deploy the App
Done! We have our very first version of the Tutorial App
ready to be deployed and used.
Click the Tutorial App
link from the previous green success message,
or the link within the header of the current case model in order to navigate to the Tutorial App
.
In the App, you should now see two models:
the Travel Request
case model and the Travel Request Form
model.
From the list of actions on the right side menu you can select Deploy
, opening the deploy dialog. Navigate to the end of the dialog and click OK
to deploy the App. This will make it available within the user dashboard, so now we can test it.
2.5. Test the App
In order to test the newly deployed App, we switch to the user dashboard.
You can do so by selecting the User dashboard
from the menu of dashboards or use the d
shortcut.
While modeling and testing, it is also a good practice to have two tabs open constantly,
one with the user dashboard and one with the modeler dashboard.
Once in the user dashboard, click Create
or type c
to open the creation dialog.
Select Create Case
and choose Travel Request
from the selection menu.
Fill out the request init form we’ve just designed. Please note the validation checks within the date picker, specifically notice that you will not be able to enter a date earlier than today.
Click the Create
button to complete creation of the new case.
You will see the newly created case displayed using the same form, as we set it for both the init and the work form.
Now you will be able to modify any values and click Save
in order to change the data for that case.
- NOTE
-
A copy of the tutorial App at this point is availble in the distribution bundle as
ModelerTutorialApp1.zip
.
2.6. Getting familiar with basic navigation
On the right side you will find available actions for the current work item (a case currently). The top right area shows the available views of the work item.
Actions, from top to bottom:
- Assign
-
lets you specify the owner and current assignee of the work item
- Share
-
lets you share the work item with one or more groups
- Start Process
-
starts an ad-hoc process within the current case
- Archive
-
closes the current work item and archives it
Views, from left to right:
- Search
-
navigates to the list of children for the current case, where you can find open tasks, documents or whatever the current case is holding
- Browse
-
navigates to the main work form of the current work item
- Comments
-
navigates to the comment section of the current work item, where you can see all existing comments as well as add new comments or reply to existing ones
- Edit Entity
-
(only available to modelers) shows a generic view with all data of the current work item and the ability to change it or even add new variables
- Edit Entity JSON
-
(only available to modelers) shows the JSON representation of the current work item, which can also be modified. Great care needs to be taken as you could break data of the work item by incorrectly modifying its JSON representation.
3. Basic process modeling
In this chapter you will learn how to create your first process, attach it to the case model created previously, and then to start it automatically when a new travel request is created.
3.1. Create new "Travel Request Process" model
Switch back to the modeler dashboard (either through the dashboard switcher or by going to your second tab with the modeler dashboard still open).
Choose the Tutorial App
if not yet open and click Create
or hit c
.
Now let’s choose Create Process Model
and enter Travel Request Management Process
as its name,
then click Create and Design
to create the process model and immediately open it in the process modeler in one step.
3.2. Getting familiar with the process modeler
The process modeler is quite similar in its basic functionality to the form designer. On the left-hand side you can find the shape palette with several sections from where you can choose process elements. The middle area is the main canvas area where you design the process. The right-hand side shows the attributes of the currently selected element in the process canvas.
You can add elements to the process by simply dragging and dropping them from the shape palette onto the canvas.
Hint: as you start modeling processes, the spacing tool
is a very handy feature to make more space in your current process model:
Activating it will allow you to easily expand sections of the process model or make a section smaller. Give it a try once you have some elements on the canvas and make yourself familiar with using the feature. Simply turn it off by clicking it once again to deselecting it.
3.3. Add a pool and lanes to the process
Let’s start the process model by adding a pool and lanes to it. This is optional in BPMN 2, but is a good practice in order to visualize the different roles, people and groups involved in the process.
Go to the Roles
section in the shape palette, drag & drop a Pool
onto the canvas and name it Travel Request Process
.
A single lane has been added automatically, double-click its label (called Lane
) and rename it to Requestor
.
Now let’s add a second lane for the travel agent managing the travel request.
Select Lane
from the Roles
section of the shape palette and drag it to the bottom part of the pool;
dropping it will add it as a second lane below the existing one.
Name it Travel Agent
. Using the spacing
tool, it’s easy to make the lanes smaller or larger according to need.
3.4. Model two user tasks as the first version of the process
We’ve now created two lanes representing two different types of people involved in the process: the requestor actually creating the travel request, and the travel agent responsible for managing the travel.
Let’s add a start event to the process by dragging the Start event
element from the Execution
section of the shape palette onto the Requestor
lane.
When an element is selected, you should see the fast-modeling
menu floating next to the element.
The start event element should still be selected, so click the user symbol from its fast-modeling menu in order to add a user task immediately after the start event.
Name it Manage Travel Request
, click on the user symbol again and name the next task Review Travel Bookings
,
then finally click the thick rounded end event in the fast-modeling
menu.
Done! We have our very first process with a start event, two user tasks and an end event, looking something like the following:
Now let’s get the tasks into the right lane simply by moving them.
Move the Manage Travel Request
task into the second lane, as it should be done by the travel agent.
Make use of the spacing tool
in order to add or remove space between lanes and elements.
3.5. Save process model and attach it to the case model
Save the process model by clicking on the Save
action in the menu bar
(we will add task forms later, so ignore any warning messages for now)
and switch to the browser tab with the process model within the Tutorial App
(not the designer window).
Navigate to the Tutorial App and select the travel request case model.
In the Autostart Processes
selection choose the newly created process model and save the case model again.
3.6. Re-deploy and test the App
We’ve now created our first, albeit simple, process model and attached it to the existing case model.
We can now re-deploy the App by using the Deploy
action as we did before
and switch to the user dashboard in order to test the changes made.
After successfully deploying the Tutorial App
, switch to the user dashboard and click Create
then select Create Case
.
Select the Travel Request
template, fill out the form and start the next travel request case.
Did you notice the gray badge in the left top corner of the children view button? It shows you that there is one child work item of the current case, which is the first task being created by the process.
Click the children list view to see that task.
The open task should be named Manage Travel Request
and behind it you should see the name of the travel request case (the same as in the header).
Navigate to the task by clicking its name. It will take you to the work form of that user task. You can still see the case in the header section of the task and use it to navigate back to the case, or you can also use the browser back button to go back. To navigate to the task, select it as the current work item. As you’ve probably noticed, this will change the available views and actions, always reflecting the possibilities with the currently selected work item.
The user task has a default form with the name of the task and a description field.
But let’s have a look at the different options available when working with the task.
There is a new view called Preview
; selecting it will display the process with a red border highlighting the current task.
Go back to the work form by clicking on the Browse button, add some notes and click Complete
.
This will complete the task and hand control back to the process engine, continuing with the process execution
and, in our case, leading to the second task being created.
You can go to the preview again and see that the process execution has now moved to the second task.
Complete the second task as well and this will finish the process execution.
You can then navigate back to the case by using the case link in the header of the task,
and check that the children view doesn’t show the badge anymore, as there are no more open tasks available.
3.7. Create user task forms for process execution
As we haven’t created specific user task forms yet, you’ll have realized that default forms were used. Of course, this doesn’t make much sense for real use and we can improve the two user tasks by designing task forms for them, showing all necessary information needed to complete each task.
Switch back to the process designer
(if still open, otherwise switch to the modeler dashboard,
select the process model and click Design
to open the process modeler).
Select the Manage Travel Request
user task.
There are two ways to create or select a form for this user task:
either click the Add reference
context menu; or, go to the attributes of the task and click the Form reference
attribute.
Here, you can choose between selecting an existing form (of course we don’t have any suitable forms yet) or creating a new one.
And that’s what we’re going to do, so choose New
.
The form designer is opened again, ready for a new form to be designed that will be automatically attached to that task.
3.7.1. Understanding the work item hierarchy
Before we start designing the new task form, let’s have a look at how the data is organized in the work item hierarchy. The process is started within the case, making the process instance a child work item of the case. If a user task is created automatically through the process, this task becomes a child element of the process. You can think of this as a hierarchy, where the case is the root, having a process as a child and the process having a task as its child:
You can store data on every work item, and every work item has also access to the data of its parent up to the root.
But of course when building form data bindings, you need to be aware of the hierarchy and where the form is actually used.
Bindings such as {{foo}}
without any prefix are always bound to the work item that form is used with.
If you want to store or read data from the case,
use the root
prefix, for example {{root.foo}}
would store or read the data from the case’s variable named foo
.
You can also use the special parent
in order to go up one level in the hierarchy of the current work item.
For a user-task, its parent
is the process the user-task is part of.
3.7.2. Show task information using an output widget
Now let’s go back to our user task form for managing the travel request.
It’s good practice to display helpful information about the current task on the task form.
As a first step, we can add an Output textarea
to it in order to display the travel request details in a read-only way.
Drag and drop an Output textarea
from the shape palette onto the form, but don’t enter a label name, just leave it blank.
Double-click the widget on the form, or click the Value
attribute, to open the rich editor to edit the content for the widget.
Let’s add something like this:
You can use formatting and add any text you want.
Of course, you can also add expressions in the same way we did with the data bindings of fields.
Please note that we are now designing the form of a user task and hence we need the root
prefix in order to
display data that is stored on the case.
Make sure you use the same variable names that you used in the case init form.
3.7.3. Add editable information to the form with a rich text area
We want the notes for the travel request not only to be shown, but also to be editable by the travel agent,
so let’s include a notes field to the form using the predefined widget named Case description
.
Drag & drop the Case description
field from the Predefined bindings
in the shape palette below the output widget on the form
and rename its label to Travel notes
.
We can now additionally add a hint in the notes field to let the travel agent know
that he should enter additional information here.
Select the travel notes field and click on the Description
attribute on the right side.
Enter something like Please add any additional information for the travel in here.
You can also directly edit that description by double-clicking it directly in the form widget.
The form should now look like this:
Save the form with the name Manage Travel Request Task Form
.
In order to re-use the output widget with all its configuration details,
select the output text area widget and copy it.
You can now close the form designer browser tab, which should take you back to the process modeler.
3.7.4. Create second task form
Switch back to the process modeler browser tab
and click on the Add reference
context menu for the second task, named Review Travel Bookings
, and again select New
.
In the new form designer, paste the output widget we previously copied from the first user task form.
Note that copy and paste is supported across models, not only within the same model, which can be quite handy for quickly modifying models.
Double-click the output widget in order to change its content to reflect the current task we want to create the form for. As this is just a review task, we’ll include the traveling notes in there directly rather than using a description field as we did in the previous form.
Now save the task form, name it Review Travel Bookings Task Form
and close the form designer browser tab.
3.8. Redeploy the App and test again
We’ve successfully added two new task forms and attached them to the appropriate user tasks in the process. So let’s test it by deploying the App again, creating a new travel request and stepping through the process.
Make sure you save the process model too before you redeploy the App, as we have also changed it to map the newly created forms!
Once you have redeployed the App, create a new case, click on the children view and select the manage travel request task. You should now see the specific task form we designed:
Add some notes, complete the task and check whether the data in the second task reflects this correctly.
- NOTE
-
A copy of the tutorial App at this point is provided in the distribution bundle as
ModelerTutorialApp2.zip
.
4. Improving the forms
In the last two chapters we created a new App, a case model, a case initialization form, a management process, as well as task forms in order to reflect our needs for the travel request case.
In this chapter we will further improve the forms, making them more user-friendly and add an attachment widget to it, then later turn it into a subform and reuse that in other forms.
4.1. Add an attachment widget to the case form
Instead of having to manually upload any booking documents, let’s place an attachment widget directly to the case form for easy access to this capability.
First, switch back to the App in the modeler dashboard, navigate to the Travel Request Form
and click Design
.
Let’s add a comment on the attachment widget for the user to understand how to use it in our context.
Drag & drop an Output textarea
to the bottom of the form,
don’t add a label, and double-click the widget to open the rich editor and enter something like this:
Below the output widget, drag & drop a new Attachment
widget from the Component
section of the shape palette and name it Attachments / bookings.
Like text data bindings, the attachment widget can also be bound to a variable, which will hold all information about any attachments uploaded.
Use the binding {{attachments}}
this time and your form should look like this:
Now let’s fine-tune the widget by selecting it and changing some attributes.
First, let’s customize the Select file message
by changing the default value to Upload any booking documents here
or similar.
Set the Preview type
to Thumbnail
, as we want to include a preview in the attachments, if possible. Set the Thumbnail maximum height
to 200
to prevent big pictures from
using too much space on the form.
4.2. Redeploy and migrate existing cases to reflect new version
Now save the case form and redeploy the App. Instead of creating a new case straight-away, let’s have a look at how versioning is done while deploying an App.
4.2.1. Understanding App and model versioning
Whenever an App is deployed, all of the models within it will be deployed to the runtime of the edoras one platform, and then they become available within the user dashboard. An App is deployed as a new version every time you deploy it, to make it fully consistent and compatible with all the models it contains. By default, the deployment mechanism uses a safe strategy of not migrating existing instances to the new models, including cases, processes and tasks. This means they will still be mapped to precisely the version they were created with until they are either completed or migrated to a newer version. So, even with an updated form in an App, existing instances of it will continue to display and use the older versions of the form.
4.2.2. Migrate existing travel request cases to latest version
For now, we want our cases to immediately reflect the latest changes within the form (the attachment widget),
so go to the Tutorial App
and navigate to the Travel Request
case model by selecting it.
Click the Migrate
action in the right side action menu of the case model, and migrate all existing cases to the latest, just redeployed, version of the App.
Switch back to the user form and select one of your previously created travel request cases to make sure they now reflect the latest version. You should see the attachment widget now:
Click the upload icon and attach an image, for example. You will have to save the case form in order to see the preview (thumbnail) of the uploaded image:
4.3. Turn the attachment section into a subform
It so happens that we also want to add the same attachment widget to the task forms. We could do this the same way as we did before using copy and paste, but this time we want to try a new feature of forms, sub forms, a great way for re-using existing parts of forms, either for technical or business reasons.
Go to the Tutorial App
and click Create
,
select Create Form Model
and enter Attachment Section Sub Form
as its name,
then click Create and Design
to directly open it in the form designer.
First, go back to the case form designer and select both the output widget and the attachment widget and copy them to the clipboard. Switch back to the new, still empty, subform and paste the widgets there. The subform should now look like this:
Save the subform and switch back to the case form designer ready to add it there, but first we need to understand how the binding works for subforms.
4.3.1. Understanding bindings in subforms
In order to use a subform in different forms and therefore different contexts, it is essential to isolate its data bindings and make them configurable outside of the subform where they are used.
Assume a subform has two fields in it with bindings to {{foo}}
and {{bar}}
.
The subform may be used within a case form as well as within a task form, displaying the same data in those different contexts.
Or the subform may even be used several times on the same form, but with different meanings
(for example, an address subform used once for the main address and again for the billing address).
In order to be able to deal with situations like this the subform itself needs a data binding as well,
following exactly the same rules as explained earlier in this tutorial.
So, for instance, if a subform is bound to {{mySubFormData}}
,
there will be a variable named mySubFormData
, which itself will be a map holding all data contained in that subform.
Example 1:
-
a subform with two fields bound to
{{address}}
and{{city}}
, respectively -
the same subform is used twice in another form
-
the first representing the main address is bound to
{{mainAddress}}
-
the second representing the billing address is bound to
{{billingAddress}}
-
-
the possible expressions (for example within an output widget) include:
-
{{mainAddress.city}}
representing the city of the main address -
{{billingAddress.address}}
representing the address data of the billing address
-
Example 2:
-
a subform with fields
{{foo}}
and{{bar}}
-
the subform is bound to
{{$this}}
(a special expression representing the context of wherever the subform is used) -
this will result in the same behavior as if the two fields had been placed on the form directly rather than within a subform
Example 3:
-
a subform with fields
{{foo}}
and{{bar}}
-
the subform is used within a case form with binding
{{$this}}
-
the same subform is used in a task form
-
we want the subform to always represent the same data of the current case
-
the subform therefore needs a binding
{{root}}
to map it to the root context to make sure it represents the same data in the task form as it does within the case form
-
Example 4:
-
same as example 3, but this time the subform binding in the case form is
{{myData}}
-
the subform binding within the task form then needs to be
{{root.myData}}
to represent the same data as within the case form
4.3.2. Understanding different types of subforms
That’s now given us the basics for the binding and isolation of data in subforms. There are also some useful possibilities of dynamically changing which form is actually used as the subform, as well as whether the subform should have one element or is able to show multiple elements.
Single-element or multi-element subform?
Subform widgets can be configured to hold exactly one element (single-element) or can hold zero to multiple elements. There is a difference is how the data is mapped in these configurations. Single-element subforms will store their data in a map directly within the variable they are bound to. Multi-element subforms will store their data into a collection (list) of maps in the variable they are bound to and are able to hold 0 to n (none, one or many) elements.
Single-type or multi-type subform?
There are basically two types of subforms available: single-type or multi-type. A single-type subform will render just one type of form for all entries it is showing. A multi-type subform can hold different types of forms and uses something called a discriminator variable to determine which form should be used for which type in the list. Assume there’s a subform showing a list of selected products. For each entry (each product), there might be a different type of form necessary in order to represent the relevant product information. The discriminator would be mapped to the type of the product, so then the appropriate product form would be used in the subform to represent that specific product the best way.
4.3.3. Adding the subform to the case form
Now having learned more about how subforms are bound to data and the different types of subforms, let’s use it in our case form to change how we represent the attachment section of the request.
Go to the form designer for the Travel Request Form
, if not already there,
and delete the output textarea and the attachment widget, as now we want to replace them with the subform we just created.
Drag & drop a Single-type subform
from the Components
section of the shape palette onto the bottom of the case form and label it Attachments
.
Click the +
button at the bottom of the widget to select the subform we want to use.
Choose Reference
and then select the Attachment Section Sub Form
as the referenced form.
Double-click the subform or click the Value
attribute to enter the binding for the subform.
As we want the same behavior as we had before without the subform,
bind it to {{$this}}, meaning the data in the subform will be directly stored in the case
(this also means we’ll even be able to migrate the existing cases without having to migrate any data).
Make sure Multiple elements
is turned off in the Specific attributes
section.
You can choose whether you want a border around the subform or not.
Turn it off to be as similar to we had before adding the subform.
Because we entered a label name for the subform (although optional), we might decide to remove the label from the attachment widget to avoid duplicate information on the form. To do so, click the subform-name-link at the bottom of the subform widget to open it directly in the form editor and make the change.
4.3.4. Redeploy, migrate and test again with the subform
Go to the Tutorial App
, deploy it again,
navigate to the Travel Request
case model and migrate the existing cases.
Switch to the user dashboard and navigate to one of your previously created cases
and you should see pretty much the same as before, but now achieved using a subform:
4.3.5. Add the subform to the task forms as well
Now we have a reuseable subform, let’s add it to both user task forms as well, so we have all the useful information available in the different contexts of the process.
Open both task forms in the form designer. There are different ways to do that:
-
Go back to the process model, open it in the process modeler, select the user task, open the attributes and click on the form reference in the
Specific Attributes
section. Then selectReference
and click theOK
button to open the form designer for the task form. -
Go to the modeler dashboard and select the form in the
My Form Models
widget. -
Navigate to the
Tutorial App
and choose the appropriate forms from there.
Once opened in the form designer, drag & drop a Single-type subform
to the bottom of the form and label it Attachments
.
As we did before with the case form,
click the +
button at the bottom of the subform and select the Attachment Section Sub Form
.
Turn off the border and make sure multiple elements are turned off. Now the binding will need to be slightly different than we used in the case form. Remember that we bound the subform to {{$this}}, meaning its data is directly stored within the case itself. In order to show the same data in the context of the task, we now need to bind it to the case, which can be done using {{root}}.
So, for the travel management task form, it should look like this:
For the second user task form, you can simply copy and paste the subform widget from the first task form (not from the case form though, as the binding is different there).
4.3.6. Redeploy, migrate and test again with the subform in the tasks
Go to the Tutorial App
, deploy it again,
navigate to the Travel Request
case model and migrate the existing cases.
Switch to the user dashboard and navigate to one of your previously created cases
(one that already has at least one attachment).
Now let’s see how we can start the process whenever we want, in an ad-hoc way. Remember that the first time the process was started automatically when we created the case. Now let’s see how this can be done manually.
Click the Start Process
action in the right hand action menu and select Travel Request Management Process
, then click Start
.
This will start a new instance of the process in the same case.
This is how processes can be manually started as an alternative to automatically starting them during the creation of a case.
As before, the children view of the case shows one task because we started the process again within the case. Navigate to the task and check, whether you see the attachments there too:
5. Ad-hoc tasks and process improvements
In this chapter we will add a requestor <–> agent feedback loop to the process. If the travel agent needs more information, clarification, decisions about which flight or hotel to choose from and the like, we will enable that by adding a feedback-loop to the process.
But first, we’ll find out how this can be done using ad-hoc tasks.
5.1. Getting familiar with ad-hoc tasks
Assuming the problem as described above, there are several options for how the travel agent could solve it:
-
Use the phone, contact the requestor and clarify the open questions
-
Send an email to the requestor and clarify anything
-
Create an ad-hoc task within the case, assign it to the requestor and clarify details
-
Add a feedback-loop to the process for better tracking and audit
The first two options are probably the way we solve many unexpected business situations, but they are not integrated in a way that any new information is automatically available within the case. In a large organization there might be a team of travel agents working together and they would need to share that information somehow, so everyone can always be up to date.
As a first step, let’s create an appropriate ad-hoc task model to support this directly within the case. In parallel to the running process, a user can create ad-hoc tasks at anytime if enabled in the case model (which is the default).
5.2. Create ad-hoc task init form
Ad-hoc tasks can be built with forms in exactly the same way we’ve created forms so far. This time, we’re going to create a different init-form.
Go to the Tutorial App
, click Create
, select Create Form Model
and name it Ad-hoc Feedback Init Task Form
.
Click Create and Design
to open the new form in the form designer.
This time we will also learn the difference between an init-form and a work-form. So far we’ve used the same form in the case for both. Additionally, we will use a subform to show the data of the case within the case form itself, a nice way to ensure all the data for a case is shown in another context.
First of all, we want to be able to set a subject for the ad-hoc task (like the subject you would put in an email).
We can use one of the predefined widgets, so drag the Name
widget from the Predefined bindings
section of the shape palette onto the form
and rename the label to Task subject
.
For the description of the task (the request for additional information, review or whatever) we will also use a predefined widget,
so drag & drop the Description
widget onto the form and rename its label to Task description
.
Click the star button of the description widget to make it required, to force the user to specify a task description.
Remember, we’re still designing the init-form of the ad-hoc task,
which is only used during the creation of the new task,
so we also want to be able to select the assignee for the ad-hoc task.
There’s a predefined widget to do exactly that,
so drag & drop the Assignee selection
widget from the Predefined selections
section onto the form
and rename its label to Assignee for the task
.
Let’s also add a due-date for the task (another default field as well),
so drag the Due date
widget from the Predefined bindings
section
and drop it onto the assignee field in the right part, splitting the row into two parts,
and rename its label to Task due date
.
Now the form should look like this:
5.3. Create ad-hoc task work form
As mentioned before, this time we want different forms for initializing (creating) a new ad-hoc task and for working on it,
so go back to the Tutorial App
, select the Ad-hoc Feedback Init Task Form
and click the Duplicate
action, as we want to create a copy of the form
so we only have to change what’s different between the init-form and work-form.
In the duplicate name field, write Ad-hoc Feedback Work Task Form
and click Ok
to copy it.
Go back to the Tutorial App
(link in the header)
and select that newly created duplicate form,
then click Design
to open it in the form designer.
Now we only have to make a few modifications to suit our needs.
It doesn’t make sense to allow the subject and description to be changed,
so let’s make them read-only by setting their attributes Editable
to false.
Next, remove the assignee selection and task due date, as we don’t want to be able to modify them.
As the requestor of the initial case, we want to be able to modify the case data itself,
so let’s add that case information by using a subform.
Previously we saw how data from the case can be shown in a task form by using an output textarea widget
and then manually add all necessary data with appropriate expressions to it.
This is one option, now let’s see a more generic
way to include the case data in the task form
by adding it as a read-only subform, using the very same form as we used for the case itself.
This way, we make sure that whenever we add new stuff to the case form,
it will automatically show up in this task form as well, because it’s a subform.
Additionally, we want to be able to choose to show and hide the case information through a checkbox.
Drag & drop a Checkbox
widget to the form,
label it Show case information
and bind it to {{showCaseInfo}}.
Select the Default value
attribute and set it to true as the default (so the case info is visible by default).
Now drag & drop a Single-type subform
below the checkbox and label it Case information
.
Click the +
button and select Reference
and then Travel Request Form
, our primary case form.
Next, we need the binding for the subform.
Remember, we want to show the case information in there, so we use {{root}}
for the binding,
which will map to the current case within which the ad-hoc task has been created.
Last thing to do is to set the Visible (RT)
attribute to the same binding as the checkbox {{showCaseInfo}}
to make the visibility flag of the subform dependent of the state of the checkbox.
Visible (RT)
means visible runtime and lets you define an expression that must resolve to either true or false, then the visibility is dynamic based on the expression’s value.
Also note that expressions are evaluated in real-time directly within the form engine of edoras one,
whenever the data that the expression is based on changes. In our case with the checkbox value,
the visibility flag is automatically adjusted appropriately.
Make sure we have Show border
set to true and Multiple elements
to false,
as there is exactly one case instance to be shown
and we want it in a border to visually indicate its data is coming from somewhere else.
The interesting part now is that we can even modify data in one single form for both the task and the case instance simultaneously, so the user doesn’t even need to be aware of context that data is coming from or being saved.
The ad-hoc task work form now should look similar to this (the attribute section is the one from the selected subform):
Now save the form and go back to the Tutorial App
for our next step.
5.4. Create ad-hoc task model
Go to the Tutorial App
and click Create
and choose Create Task Model
.
Set the name to Travel Feedback Task
.
Now select the appropriate init-form and work-form in the Init Form
and Work Form
selections of the task model
and complete creation of the model by clicking Create
.
5.5. Deploy App and test ad-hoc task
Navigate back to the Tutorial App
and deploy it again, which will make our new ad-hoc task available for use.
Switch to the user dashboard and select one of your previously created travel request cases.
Now click Create
and choose Create Task
.
If you do that in the context of a currently selected case,
it should be automatically preselected in the Parent Case
selection.
Now choose the Travel Feedback Task
Template,
fill out a task subject and description,
choose yourself as the assignee (so you don’t have to logout and login to complete it)
and optionally also choose a due-date.
Click Create
to create the ad-hoc task.
If you check Create another
before hitting Create
,
the new task will be created and you will return back to the same init-form so you can quickly create another one.
Going to the newly created ad-hoc task there are several things you should note.
First of all, you should be able to show and hide the case information by simply clicking the Show case information
checkbox.
Also note that the information in there reflects the case information
and you are able to modify it directly while in the task.
You can test that by changing some case information in there,
clicking Save
(not Complete
yet) and navigating to the case.
The data in the case itself should have been updated accordingly.
To complete the task, simply click Complete
and it will be finished.
By default, completed tasks are not shown in the children list of a case.
If you would like to see them,
go to the children list of the case
and select status All
within the search box.
Now you will see all work items of the case, even completed ones.
5.6. Add feedback loop to the process
As an alternative to the ad-hoc task approach we just tried, we now want to incorporate the agent <→ requestor feedback loop directly into the management process.
And here is how we can do it:
-
Add a
next step
selector in the management task form, to let the travel agent choose between different options (need more information, travel organized, and so on) -
Add a gateway in the process after the user task to take the appropriate sequence flow based on the selected next step
-
Add feedback-task as a new path in the process that loops back to the management task
-
In the review task at the end of the project, add a new checkbox to the form to give the requestor the option to loop back to the agent if he is not happy with how the travel has been organized
5.6.1. Add next step selection option to management task
Navigate to our travel request management process
and open it using the Design
action (if the process modeler is not already open).
Open the process model in the process modeler, select the Manage Travel Request
user task, open the attributes and click on the form reference in the Specific Attributes
section. Then select Reference
and click the OK
button to open the form designer for the task form.
In order to separate the previous form elements from the next one,
drag a new Horizontal line
from the Component
section
and drop it right after the Travel notes
field.
Drag a Static select
widget from the Component
section onto the form between the travel notes and the attachment subform, and drop it inbetween.
Label it Select next step
and bind it to {{parent.nextStep}}.
Why did we use the parent
prefix?
Note that our form is used within a user task created as part of a process.
If we want to be able to use the data in the nextStep
variable in the process context,
we must not store the data in the local task context,
but rather in the process context (parent
-prefix) or even the case context (root
-prefix).
As this information is only needed during the lifecycle of the process,
we’ll to store it in the parent process and not in the root case context.
Let’s make the selection mandatory by clicking the red star or setting the attribute Required
to true.
Now open the Options
attribute dialog by clicking its attribute value, then enter two options in there:
-
Name:
Need more information from requestor
, Value:moreInfo
-
Name:
Finish organization, travel has been fully organized
, Value:finish
The name column defines the label used for that option, while the value column is used to define the variable to store the selection.
If we choose the first option, we want to show a new note field
where the agent can describe what kind of information is needed from the requestor.
So let’s drag & drop a Rich textarea
from the Components
section of the shape palette to below the selection widget on the form
and label it Information request
.
Make that field required by clicking the red star,
but note that the required-validation will only take place if the field is shown;
if it stays hidden, there is obviously nothing to be entered and the validation takes this into account.
Bind the field to {{root.infoRequest}}
,
as we want to keep that information, even after the process has been ended.
We’ll store it within the case context and that’s why we’ve used the root
prefix instead of parent
that we used with the nextStep
variable.
As we are already thinking ahead to when the feedback loop returns from the requestor back to the agent,
we want to show the information the requestor entered,
so let’s add an output textarea showing that information.
Drag & drop a new Output textarea
below the information request field
and leave the label empty.
Double-click it and add the following content to it:
We only want to show the information request field if the next step selected is moreInfo
,
so select the Information request
field and enter {{parent.nextStep=='moreInfo'}}
in the Visible (RT) attribute,
making it visible only if we select Need more info… in the next step selection.
The output text area should only be visible if it has content,
so let’s enter {{root.infoRequestAnswer}}
in the Visible (RT)
attribute,
making it visible only if the variable root.infoRequestAnswer
has content.
The form should now look like this:
5.6.2. Add feedback loop to the process model
We now have to add the feedback loop to the process model, so let’s open it in the process designer.
Still remember the spacing tool
?
We can make use of it now to add some extra space after the management task
in order to add the gateway after the user task.
Now drag a new Exclusive gateway
from the Execution
section of the shape palette
and drag it over to the sequence flow after the user task.
As soon as the sequence flow becomes green we can drop it, as the modeler has recognized that we want to drop it inbetween the two user tasks.
As you can see, the modeler automatically splits the sequence flow into two and adds the gateway inbetween.
Select the gateway element (if not already selected) and drag & drop the small user task icon to add another outgoing sequence flow with a user task after the gateway:
Name the new user task Answer Info Request
and align it right above the gateway
and on the same horizontal level as the other requestor task:
Select the new user task
and drag the arrow icon next to it onto the Manage Travel Request
user task until it turns green,
then drop it to connect the two tasks with a sequence flow.
We’ve now successfully modeled the feedback loop after the gateway. Our next step is to tell the engine which flow to use from the gateway by specifying conditions on all outgoing sequence flows.
Select the sequence flow between the gateway and the Answer Info Request
user task,
then click on the Condition expression
attribute
and enter #{nextStep=='moreInfo'}
as the expression.
We’ll explain the different expression syntax in just a minute,
but first let’s add a label to the sequence flow.
This can be done by clicking the Name
attribute and entering the name,
or simply by double-clicking the sequence flow directly in the process canvas.
Let’s name it more info
.
Now select the sequence flow between the gateway and the Review Travel Bookings
user task and enter #{nextStep=='finish'}
as the Condition expression
attribute and name it finish
.
It’s good practice to add a label to a gateway element, so double-click the gateway and type Decision?
5.6.3. Getting familiar with frontend and backend expressions
You probably noticed that there is a difference in the syntax for frontend expressions used within forms and backend expressions as we’ve just used in the process model. The difference is down to where they are being evaluated: directly within the browser (frontend / forms), or on the server (backend, everywhere else, such as process, email templates, document templates, and so on). Frontend expressions are limited to whatever the browser and form engine know, in contrast to the expressions on the server side, which could contain your own service calls, functions, any navigation through the work item network and much more. That’s why we use different syntaxes, to make the difference in their evaluation very prominent to the modeler.
But now, back to our sequence flow condition #{nextStep=='moreInfo'}
.
Why didn’t we use parent.nextStep as we did in the form?
It’s very important to always remember in which context an expression will be evaluated.
In the user task form we are in the context of a task work item,
which is a child element of the process work item.
The expression on the sequence flow, however, is evaluated in the context of the process itself
and therefore we don’t need the parent
prefix that we needed in the task context.
5.6.4. Create user task form for the answer task
We now have to create the user task form for the new task added to the process.
If you remember, you can simply click the icon,
select
New
and it will create a new form,
attach it to the user task and open it up within the form designer.
Let’s add an Output textarea
to the form
so we can add the necessary information in there.
Leave the label empty, double-click the widget
and add the following content to it:
Note that we can include expressions anywhere within the content as we like.
Below the output field, add a new Rich textarea
widget,
label it Your answer
and bind it to {{root.infoRequestAnswer}}
(the same expression we already used in the management task form).
Additionally, make it required by clicking the red star icon.
The form should now look like this:
Save the form, name it Answer Info Request Task Form
and close it in order to return back to the process design.
Save the process model as well, with the new feedback loop, in order to test it.
5.7. Redeploy and test process with feedback loop
Go back to the Tutorial App
and redeploy it.
Now switch to the user dashboard and create a new case with our Travel Request
template.
Did you notice the new attachment widget was also visible in the init-form?
If you don’t want to be able to upload attachments while starting the travel request,
just add {{root.id}}
within the Visible (RT)
attribute of the subform widget holding the attachment subform in the Travel Request Form
.
It will not show up as long as the case hasn’t been initialized, because the root.id
variable is not available.
If you navigate to the Manage travel request
task within the children view of the case
you will see the updated management task form.
Select Need more information…
from the Next step
selection
and the new Information request
field should appear,
where you can enter the information you need from the requestor:
Did you notice the rich text capabilities within the text editor? When selecting part of the text, a toolbox appears that allows you to change the formatting:
If you now click Complete
, the next task will be the answer info request task,
where you can provide an answer,
after which the process will go back to the management task.
You can use this feedback loop as many times as you want.
As soon as you choose Finish…, the process goes to the review task and will finish.
Did you notice the pre-selected next step combobox when returning back to the management user task? Remember that we bound the selection of this widget to parent.nextStep, and as the selection is stored in the process it will be remembered the next time that information is used again. As we don’t wont that behavior, let’s go back to the process and add a service task to reset its value before we return to the management task again.
5.7.1. Add service task to initialize variables to the process
Make some more space before the Manage Travel Request
user task in order to add a service task there.
Afterwards drag a new Initialize variables
task from the Service tasks
section onto the sequence flow between the start event and the user task,
drop it and name it Reset next step selection
.
Move the sequence flow connection that’s between the answer and the manage task so it points to the new reset service task by selecting the connection and dragging the green point at the end of the flow arrow, dropping it onto the reset service task. If you want to rearrange the sequence flows, there are several handles available to choose from. There is a red point on every bend of the sequence flow to allow you to move the bend location. Adding a new bend is easy too, simply click anywhere on the sequence flow and drag the red point that appears. You can move a sequence flow in parallel by moving the red rectangle that appears in the middle of the flow.
Your process model should now look like:
Of course, we still need to tell the engine which variables to initialize within the reset service task we just added.
Select the service task and click the Init variables
attribute,
in the dialog that appears, enter the variables we want to initialize or reset for our case.
The first column can be left empty as our nextStep
variable is in the process scope.
Write nextStep
in the variable name column and leave the last column empty as well
as we simply want to clear the previous selection value.
If you also want to clear the previously entered information request text,
add an extra row to the dialog which should then look like the following: