
This is a continuation of the
article about the device of a small application created on the
CUBA platform. The application is a system of accounting for home finances and was created with a twofold goal: firstly, to actually account for my finances, and secondly, to illustrate the possibilities of the platform with a simple example.
In the first part, I talked about the main parts of the application: the data model, the business logic of the middle layer, and the screens created on the Generic UI platform technology. In the second part, as I promised, I will talk about how to change the Generic UI theme, how to change the behavior of the visual component, and describe the device of an additional UI for mobile devices written in JavaScript.
')
To begin, let me remind you what tasks the application solves:
- At any time shows the current balance for all types of cash: cash, cards, deposits, debts, etc.
- Generates a report by income and expense categories, which allows you to find out what was spent on or where the money came from in a certain period.
The source code of the application is on
GitHub , the instructions for building and running are in a previous
article . The CUBA platform is not free, but five simultaneous connections in a free license are enough for home use, so if someone wants to use it, please.
To study and refine the application, I recommend
downloading and installing CUBA Studio, IntelliJ IDEA and CUBA plugin for it.
UI Theme
Let's start with a simple one - how to change and customize the theme of the main UI application.
A lot of time passed since the first part of the article was released, and we managed to release a new version of the platform - 5.3, in which we added a new Halo theme. It is based on the theme of
Valo Vaadin framework, and in addition to the fact that it looks nice and scales well, it is also very easy to customize. In particular, to completely change the color gamut, only a few SCSS variables need to be redefined.
So, it was enough for me to transfer the application to a new version of the platform, and now the user of the system can choose the theme of the old Havana or the new Halo in the
Help> Settings window.
In the new theme, the application looks like this:

This is the default theme setting. The only thing I added was the style of numbers of the final balance in the left pane. For this, the LeftPanel class for the Label components used to display the totals, is given the name of the style: totals. Then, using CUBA Studio, I created the Halo theme extension. At the same time, the themes / halo subdirectory in the web module appeared in the project, where you can override the theme settings. To define the totals style, the following CSS code has been added to the halo-ext.scss file:
.v-label-totals { font-weight: bold; }
The class name for the selector is most easily determined by the browser in a running application.
Halo theme is easy to adapt to your taste. I have no design abilities, therefore I will give only an example of the definition of a dark color gamut:

For such a theme change, the following variable values ​​have been added to the halo-ext-defaults.scss file:
$v-background-color: #444D50; $v-support-inverse-menu: false;
Similarly, using theme variables you can change the font size of various elements, indents, table parameters, etc.
An interesting feature of the Halo theme is that it uses Font Awesome font glyphs for the icons of the standard components of the platform. In addition to the obvious advantage when scaling, this also allows you to automatically select the color of the icons depending on the background color — in the example above, I did not have to define a new set of icons for a dark background.
Customization of visual components
We now turn to the possibilities of changing the behavior of visual components, and more specifically, the client code of components running in the browser. The CUBA components in the web client are implemented on the technology of the Vaadin framework, so the main method of developing the client-side of the components is using Java and compiling in JavaScript using GWT. This is an extensive topic and requires a separate article, so here I will consider a simpler option - extending the component by implementing additional logic in JavaScript.
We formulate the problem. Now the operation amount field allows you to enter an arithmetic expression that is calculated in the screen controller using the AmountCalculator class while saving the operation. That is, all this happens on the server side. The task is as follows: by pressing the “=” key in the amount field, calculate the expression on the client (in the browser) and immediately display the result in the field.
It is easy to calculate an arithmetic expression in JavaScript: check the expression for validity using a regular expression, and then execute it via eval (). The main question is how to connect your JavaScript to the right place in the client code of the application? In Vaadin, starting from version 7, there is a special component extension mechanism for this, more specifically, the AbstractJavaScriptExtension class. I took advantage of them.
In the web module, a Java class CalcExtension, inherited from AbstractJavaScriptExtension, is created. All he does is to take a TextField instance in the constructor and pass it to the extend () inherited method, that is, “extend” it in some way. In addition, this class has a JavaScript annotation with the name of the file in which the client logic is written in JavaScript.
The extension is connected to the com.vaadin.ui.TextField component obtained from the TextField CUBA component in the initAmount () method of the AmountCalculator class:
The textfieldcalc.js file is located in the web / VAADIN directory of the web module. When building an application, it is automatically copied to the VAADIN directory of the web application — there are also GWT widgetsets, themes, and other resources. The file defines a global function with the name corresponding to the full name of the Java extension class, but with dots replaced by underscores.
This function is called when the component is initialized, and this will point to a special object through which it interacts with the framework. The methods of this object are described in JavaDocs on the AbstractJavaScriptExtension class, and with their help you can get a DOM element that implements the component, in this case, input. Next on the element with the help of jQuery event listener is hung, performing the necessary actions. The result is achieved - when the user presses the “=” key (code 61), the expression in the field is calculated and the result is put back in the field.
Additional JavaScript UI
In the practice of developing applications for CUBA, an additional front-end is usually created for “external” users: customers, mobile workers, etc. These are either websites or mobile applications with specific design and usability requirements, which dictates the use of low-level native technologies. Such an additional UI requires an order of magnitude more effort in development and support than the CUBA Generic UI. Fortunately, the required functionality of an additional UI is usually much less than the functionality of the entire enterprise information system.
In the described application, additional responsive UI on Backbone.js + Bootstrap is used for convenience on mobile devices. It allows you to only enter transactions and see the current balance. The report on categories and management of directories are not implemented, filtering and sorting operations too.

Consider first the server side.
The CUBA includes the portal module, which includes, among other things, a universal REST API for working with the data model. Through it, the main interaction of the client JavaScript application with the middle layer goes. Only two additional API methods were created in the project: getting the current balance and getting the last used account. Everything else is implemented by a universal API.
To use the REST API in your project, you need to create a portal module in it. The easiest way to do this in CUBA Studio is with the
Create portal module command in the
Project properties section. This also creates a web application harvesting on Spring MVC, which serves as an example of authentication and work with the middle layer. In our application, this stub is not used, so everything except the PortalController class and configuration files in the src root are removed.
The PortalController class is a Spring MVC controller and contains two methods: getBalance () and getLastAccount (), called via HTTP GET. These are the methods that supplement the standard REST API of the platform, and they are implemented in a similar way: first, authentication, then the logic of the method, including calling the middle layer services and generating the result in JSON. Thus, the main logic of the method is executed in the context of a user session, the key of which is transferred in the parameter of the method.
The standard REST API of the platform includes login and logout methods, getting entities by ID and JPQL query, committing changed instances - in general, everything for CRUD operations. Combined with the two specific methods of the PortalController class, this is enough for the client JavaScript application to work.
Go to the client side of the additional UI.
The client code is located in the web / akkount directory of the portal module. It is loaded into the browser using the PortalDispatcherServlet servlet, the configuration of which is in the portal-dispatcher-spring.xml file.
Actually, the application consists of a single host HTML file and a set of models and views of Backbone.js. The layout and layout are made on Bootstrap, a few specific CSS is in the css / akkount.css file. The main.js script is the entry point to the application — it initializes the Backbone router located in the router.js file. In addition, main.js contains some common functions, variables, and constants.
Authentication works as follows. After login, the session key received from the server is stored in the main.js script variable and in sessionStorage. When reloading the page, the key is taken from sessionStorage, cookies are not used. If an error 401 was received during the execution of operations (the session key is invalid due to session expiration on the server), then a redirection to the login view occurs. For permanent storage of the user name (if the checkbox in the login window is checked) localStorage is used.
Of interest may be the way of exchanging data between the Backbone.js models and the middle layer of the application through the standard CUBA REST API. To do this, the Backbone.sync () function is overridden in the main.js script, and it delegates the synchronization to the cubaAPI object located in the cuba-api.js file.
For the cubaAPI object's methods to work, Backbone models must contain some additional fields: entityName, jpqlQuery, maxResults, view. They are used to form the corresponding query parameters in the loadList () method. In the update () and remove () methods, JSON is simply generated with the commitInstances or removeInstances property, respectively.
CUBA REST API is capable of returning object graphs with circular references in JSON. To do this, an object that is present in the path from the root more than once is replaced by an object with the ref attribute equal to the identifier of the repeating object. In order to replace such ref objects with real objects, cubaAPI has created the parse () method, which overrides the parse () methods of models and collections Backbone.js.
The initialize () function of the model was also redefined in order to generate entity identifiers in the form ready for transmission to the CUBA REST API:
The rest of the additional UI is built quite standard for Backbone.js way.
Thanks for attention!
In our immediate plans, we will publish articles on the creation of visual components for CUBA on GWT and on the tool developed by Haulmont to support the resiliency of PostgreSQL servers.