Important: To complete this tutorial, you need the Enterprise Edition of Designer and the LSPS Maven Repository installed.
Typically, the default To-Do list will not cut it in the real world of business and you will require custom business-related data for a to-do while retaining the related mechanisms, such as, priority of the todo, its allocation, locking, annotations, delegation, substitution, etc.
Since the Todo is represented by the Todo
record which is a system record, you cannot simply add a field to it. However, you can create a new Record related to the Todo Record and add the business data to this Record: in this tutorial, we create the TodoItem
record with an additional field and a relationship to the Todo
record:
issueAction
parameter of the User tasks.Note: The pattern of records related to system records can be applied analogously to other system records, for example, to extend the data held by
Person
.
Before you start, create a project:
custom_todo_list_model
and click Finish.Since Todo is a system record and system records cannot be extended directly, you need to create a record that will represent our todo item with the business data and is related to the Todo system record:
custom_todo_list_model
project.custom_todo_list_data
.TodoItem
:TodoItem
.priority
of type Integer into the TodoItem
record.todo
) and click OK. todo
Single
(one TodoItem relates to one Todo) Note: To display the fields and methods of the imported Todo record, right-click the record and under Compartments select the required items.
Todos are created when a User Task of a process instance is executed: to create the todo item related to the todo, create it in the issueAction
closure of the User Task: issueAction is executed right after a todo is created and has the todo created by the User Task as its input parameter.
Let's create a process that will create a Todo and its TodoItem:
custom_todo_list_process
and click Finish.CreateTodoItem
and select the BPMN-based process option.newTodoItem
of the TodoItem type (in the Outline view of the process definition, right-click the root node and select New > Variable). It will hold the new todo item, so we can pass it to the todo form where we will edit its priority field.issueAction
parameter, create the TodoItem record over the to-do: SubmitForm
does not exist yet; we will create it in the next step.Note: If you attempted to change the value of the related to-do directly, for example, on a flow assignment with
newTodoItem.todo.title := "";
, you will get a validation error since Todo is a system record and fields of system records cannot be accessed directly.
Create the form that will be used to gather the priority data for the TodoItem and submit the todo:
custom_todo_list_process
module and go to New -> Form Definition.SubmitForm
as the name of your form and make sure the Use FormComponent-based UI is selected. Note: The Use FormComponent-based UI setting defines the module of the Standard Library that is used to create the form: When the option is selected, the forms module is used. Such forms are created more like in Vaadin and are a more powerful solution. When not selected the ui module is used. forms based on the ui module are used. Such forms are event driven and oriented on users without programming skills.
TodoItem
(in the Outline view of the form definition, right-click the root node and select New > Variable).public SubmitForm(TodoItem newTodoItem){ newTodoItemVar := newTodoItem }
"Priority:"
&newTodoItemVar.priority
"Submit"
{ e -> Forms.submit()}
Now we will create a page that will display the list of the todo items that have not been submitted yet (their todo is alive) and are assigned to the current user.
First, create a query that will retrieve todo items:
getTodoItems
, set TodoItem
as the record type, and set an iterator name, for example ti
.t
.The query is ready and you can create a document with a form that will display the todo items:
custom_todo_list_ui
non-executable module that will hold the document.todoItemsList
"My Todo Items"
new ListOfTodoItems()
ListOfTodoItems
and click Finish.getTodoItems()
as its value.TodoItem.todo.id
, TodoItem.priority
.{ ti:TodoItem -> Forms.navigateTo( new TodoNavigation( todo -> ti.todo, openAsReadOnly -> false ) ) }
guest
user with all security roles.http://localhost:8080/lsps-application
, log in as the guest userNow this is all nice and neat but the user can still access the default To-do List page: so we need to substitute the To-Do List in the Application User Interface with our to-do item list. To do this, we need to modify the Application User Interface itself.
First, generate LSPS Application:
For more details about the sources, refer to the custom-application documentation.
Let us remove the default To-Do List item and add our list item to the navigation menu:
<YOUR_APP>.vaadin.core.AppAppLayout.java
class.createMainMenu()
method so it returns you custom MainMenu implementation. @Override protected Component createMainMenu() { return new AppMainMenu(CONTENT_AREA_ID); }
createMenu()
method.@Override @SuppressWarnings("unused") protected void createMenu() { /*if (ui.getUser().hasRight(HumanRights.READ_ALL_TODO) || ui.getUser().hasRight(HumanRights.READ_OWN_TODO)) { todoMenuItem = navigationMenu.addViewMenuItem(TodoListView.TITLE, TodoListView.ID, FontAwesome.LIST, todoBadge, null); }*/ ...
Important: Note that this is a different server from Designer Embedded Server we used previously. The Designer Embedded Server is generated on its first launch in the given workspace with the default LSPS Application deployed. The SDK Embedded Server is generated when you generate your application in the and has your application hot-deployed.
Now add the navigation item to the custom to-do list:
createMenu()
of AppMainMenu.java
: paste the qualified name of the document to prevent typos. //navigation item to the todo item document: if (hasRightToOpenDocument("custom_todo_list_ui::todoItemsList")) { navigationMenu.addDocumentItem("Todo items", "custom_todo_list_ui::todoItemsList", null, VaadinIcons.ABACUS, null, null); }
custom_todo_list_ui
module and run the custom_todo_list_model
module to create some todo items.The document menu item is now in the navigation menu but its label contains the ???
characters: these signalize that the system failed to find the localization string. Let's create the string:
addDocumentItem()
call: navigationMenu.addDocumentItem("nav.todoitems", "custom_todo_list_ui::listOfTodoItems", null, FontAwesome.ADN, null, null);
com.whitestein.lsps.vaadin.webapp
package (<YOUR_APP>-vaadin
project).Right now the document with the todo items is accessible not only from the dedicated navigation menu but it is also available as a document on the Documents page. To remove it, do the following:
@Override protected void createNavigator(ViewDisplay display) { Navigator navigator = new AppAppNavigator(getUI(), display); }
public AppAppNavigator(UI ui, ViewDisplay display) { super(ui, display); }
documentsViewClass()
to return your document view class: @Override protected Class<? extends AppView> documentsViewClass() { return AppDocumentsView.class; }
DocumentsView
class (copy the content of the class to AppDocumentsView and adjust the load()
method so it excludes the todo list document: //added property for excluded documents: private static final String EXCLUDED_DOCUMENT = "custom_todo_list_ui::todoItemsList"; ... private void load() { try { //Add documents; renamed original documents to allDocuments: List<DocumentInfo> documents = new ArrayList<>(); List<DocumentInfo> allDocuments = genericDocumentService.getNonParametricDocuments(); //checking in the list of all documents for the excluded documents: for (DocumentInfo document : allDocuments) { //Added this if to excludes the document from the table: if (!EXCLUDED_DOCUMENT.equals(document.getId())) { documents.add(document); } } this.documents.clear(); this.documents.addAll(documents); } catch (ErrorException e) { getUI().getAppErrorHandler().showErrorMessage("app.unknownErrorOccurred", e); } }
documentBadge
on documentMenuItem
(the blue icon with the number of available documents).Simple example of badge calculation
//constant with the document name: private static final String DOCUMENT_IN_MENU = "custom_todo_list_ui::todoItemsList"; @Override protected void calculateBadges() { todoBadge = (int) todoService.getTodoCount(new TodoListCriteria()); try { List<DocumentInfo> nonParametricDocuments = documentService.getNonParametricDocuments(); //exclude of the document from the count: documentBadge = 0; for (DocumentInfo documentInfo : nonParametricDocuments) { if (!DOCUMENT_IN_MENU.equals(documentInfo.getId())) { documentBadge++; } } } catch (ErrorException e) { throw new RuntimeException(e); } runModelBadge = (int) modelManagementService.getExecutableModulesCount(); } @Override protected int getDocumentBadge() { return documentBadge; }