Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Reports

In Kuwaiba, reports are HTML documents designed to provide detailed information about the objects that are part of the inventory. Their purpose is to inform and follow up on specific situations. As of version 1.1, users can create their own reports using groovy scripts, usually in three steps:

  1. Retrieve the data: Either by performing a query directly on the database or by using the high-level API provided by Kuwaiba. In the first case, the user will have to handle the raw nodes and relationships contained in the graph database and will most likely have to use Cypher. In the second case, he will have to use the documented Java API.
  2. Information processing: Consists of taking the data retrieved in step 1 and performing calculations, filtering and other processing to convert it into meaningful information.
  3. Formatting and visualization: This consists of creating a structure of tables, labels and/or graphs to present the information in a way that is clear and easy to read.

To access the reports module, locate in the menu presented at the top of the screen the Others section, represented with the list symbol icon. When accessing this section, a vertical menu will be displayed where you can see the Reports module, as shown in Figure 1.

access report
Figure 1. Access to reporting module.

There are two types of reports: class level reports and inventory level reports. Both are explained in the following subsections.

Class Level Reports

These reports are linked to the instances of a given class. From the reports module you can view the class level reports by clicking on the Class Level Reports option indicated in the red box in Figure 2, where all the existing class level reports are listed.

access report
Figura 2. Class level reports.

To filter the reports by class, use the search bar indicated with Choose a Class in Figure 3. Here you can view all available classes by clicking on the list class button and select one, either by searching directly in the drop-down list or by entering the class name. When selecting a specific class, such as Rack, only the reports corresponding to that class will appear, as shown in Figure 4.

access report
Figure 3. Class selection.
reports by class
Figure 4. Reports by class.

To create a new report, select the create report button shown in Figure 2. Clicking on this button will open a new window (Figure 5) where you can choose the class to which the report belongs, enter the name, a description and choose the type of report, which in this case is available only in HTML format.

reports by class
Figure 5. Create class level report.

Note. If you have previously filtered the reports by class before creating a new one, when you open the creation window, the Class Name field will default to the class that was selected in the filter.

Important. In the Type field of Figure 5, when displaying the list of possible types, CSV, PDF, among others, appear. These formats are not yet natively supported, but you can export to PDF an HTML report from your browser, and it's also possible to generate raw text instead of an HTML document if you need a CSV format. Likewise, you can copy the tables in your HTML report and paste them on an Excel sheet almost transparently

To view and modify the contents of a specific report, select it. The contents of the report are displayed on the right side of the screen, as shown in Figure 6.

reports by class
Figure 6. Report content.

The right side of Figure 6 shows the Groovy script used for the specific report, which can be edited directly from this window.

In the upper right part of Figure 6, three buttons can be seen. This image is expanded in Figure 7.

options
Figure 7. Report options.
  • The icon edit allows the user to modify the properties of the selected report. Clicking on it opens a new window as shown below, where the user can change the name of the report, modify its description, and enable or disable the report.

    options
    Figure 8. Edit report properties.

    Important. The Enabled button allows you to enable or disable the report, which determines whether it can be executed or not. A report can only be run if it is enabled. When a report is created, it is enabled by default.

  • The icon save allows you to save the changes made to the script. If the user has modified the Groovy script of the report, it is necessary to select this button for the changes to be saved.

  • The icon delete deletes a report.

A class-level report is designed to apply to all inventory objects that belong to a specific class. To run this type of report, you can run it from any inventory object that is part of that class. For example, if we select an inventory object that belongs to the Rack class, from the Navigation module (detailed in the Navigation chapter), we search for a Rack. In the object's options panel, we find the basic actions available, where the option called Reports is included, as shown in Figure 9.

object_report_option
Figure 9. Reports option in the object's options panel.

When selecting the Reports option in Figure 9, a new window appears with the reports associated to the Rack class (reports that can be executed from this object, as shown in Figure 10).

reports
Figure 10. Available reports.

When a report is selected, a new tab opens in the browser with the HTML output of the report.

result
Figure 11. Report result.

Note: Reports belonging to abstract classes are applicable to their subclasses. For example, if a report is created for the GenericLocation class, it will be available for its subclasses such as Building, House, Neighborhood, among others.

Inventory Level Reports

These reports are not linked to inventory objects. Instead, they are used to display general purpose information, such as "All support contracts about to expire" or "All inventory objects with operational status Defective". For these reports, custom parameters can be defined, unlike class-level reports that only have the object that starts the report as a parameter. Parameters are always captured as strings, and it is necessary to parse and ensure that they match the correct format at the start of the report.

To view the existing inventory level reports, select the Inventory Levels Reports option that appears in the reports module, as shown in Figure 12. This will list all existing inventory level reports.

inventory_reports
Figure 12. Inventory level reports.

You can filter the reports by name, in case you need to search for a particular report, in the filter field shown in Figure 13. If you select the list class symbol, all the reports listed will appear and, as you type in the search bar, the results shown in the list will be limited to your search.

filter
Figure 13. Inventory level report filtering.

You can create inventory level reports by clicking on the create_inventory_report button, which will open a new window where you can enter the name, a description and choose the type of report, which in this case is available only in HTML format.

create_inventory_level_report
Figure 14. Inventory level report filtering.

Important. In the Type field of Figure 14, when displaying the list of possible types, CSV, PDF, among others, appear. These formats are not yet natively supported, but you can export to PDF an HTML report from your browser, and it's also possible to generate raw text instead of an HTML document if you need a CSV format. Likewise, you can copy the tables in your HTML report and paste them on an Excel sheet almost transparently.

To view and modify the contents of a specific report, select it. The contents of the report are displayed on the right side of the screen, as shown in Figure 15.

report_content
Figure 15. Content of an inventory level report.

The right side of Figure 15 shows the Groovy script used for the specific report, which can be edited directly from this window.

In the upper right part of Figure 15, there are four buttons, detailed below.

reports by class
Figure 16. Inventory level reporting options.
  • As in the previous case, the edit button allows the user to modify the properties of the selected report. Clicking on it opens a new window as shown below, where the user can rename the report, modify its description, enable or disable the report and add or remove parameters.

    edit_inventory_report
    Figure 17. Edit report properties.

    Important. The Enabled button allows you to enable or disable the report, which determines whether it can be run or not. A report can only be run if it is enabled. When a report is created, it is enabled by default.

  • The save icon allows you to save the changes made to the script. If the user has modified the Groovy script of the report, it is necessary to select this button for the changes to be saved.

  • The icon delete deletes a report.

  • The icon execute runs the report and opens a new tab in the browser with the HTML report output.

How to Create Scripts

Creating complex scripts requires some knowledge about the Persistence API and the database structure. It’s out of the scope of this document to deeply explore these topics, but this section will give you a starting point. More documentation and examples will be published in the coming releases; for now, use the reports provided in the directory scripts in the client installation bundle as reference.

  • Kuwaiba uses Groovy as scripting language. Its syntax is very similar to Java’s, but it’s optionally typed. We recommend you to use an external editor that supports Groovy syntax recognition such as Notepad++ (Windows) or GEdit (Linux/MacOS) to write your scripts, then copy the text to the corresponding field in the report properties.

  • All scripts must return an HTMLReport object. This class and the others that are used to build the report are located in the package org.neotropic.kuwaiba.modules.optional.reports.html. There are wrappers for the most common HTML tags, and constructing a report consists of nesting instances of these classes in the right order.

  • The following variables are injected in the script and can be used at any moment:

    Variable NameTypeNote
    instanceNodeNeo4jNodeOnly applicable to class level reports. It’s the node in the database that holds the information of the object that triggered the report.
    graphDbNeo4j GraphDatabaseThe reference to the connection handler. This gives complete access to the database. Use with caution.
    classNameStringOnly applicable to class level reports. The class of the object that triggered the report.
    objectIdLongOnly applicable to class level reports. The id of the object that triggered the report.
    parametersHashMap[String, String]Only applicable to inventory level reports. The list of parameters provided during the execution of the report.
  • There are some built-in reports that could serve as reference on how to retrieve and manipulate the information from the database. They are a temporary solution and will be converted to actual scripts in future releases, but they can help you get started on how to use the Persistence API.

  • Sample Reports can be found in https://sourceforge.net/p/kuwaiba/code/HEAD/tree/server/trunk/scripts/reports/, where report-related scripts have the prefix RP in their name.

Basic Concepts

To create a report, it's important to understand how they work. Reports are built modularly by adding HTML tags, each of which displays information and applies its own logic

To build a report, the first step is to create the instance

   def report = new HTMLReport(String.format("Report's name","", "1.0"))

Next step is choose an HTML tag to display information, the options are:

  • Text: Text is an HTML tag where is possible show a information, error or warning message. To create a message is:

    def message = new HTMLMessage(cssAttributes, null, text)
    

    If want to add a variable in message use String.format(), for example:

    def message = new HTMLMessage(cssAttributes, null, String.format("put your text %s",variable))
    

    Where: cssAttributes represents the ccs styles applied to the text separated by semicolons(;), for example:

    def cssAttributes = "color:black; font-weight: normal; font-size: 2em "
    
  • Table: Table is an HTML tag where is possible show a information in format table with rows and columns. To create a table is

    def table = new HTMLMTable()
    

    To add values to table use the method table.getRows().add(), but are two possibilities when the number of rows is known: the table is created by defining the name of the columns and the value of the row at the same time.

    In the case when the number of rows is known, the table is created by defining the name of the columns and the value of the row at the same time. For example:

    generalInfoTable.getRows().add(
      new HTMLRow(cssAttribute, null, 
          [
              new HTMLColumn(cssAttribute, null, text),
              new HTMLColumn(value)
          ] as HTMLColumn[]));
    

    Note

    • The first new HTMLColumn represent the name of column and new HTMLColumn is the value
    • It is mandatory to cast the content to HTMLColumn
    • cssAttributes represents the ccs styles applied

    When the number of rows is not known, first define the name of the columns:

    table = new HTMLTable(null, null, ["COLUMN1", "COLUMN2", "COLUMN3"] as String[])
    

    Note:

    • It is mandatory to cast the content to String

    After, add row's value:

    table.getRows().add(
      new HTMLRow(null, null, 
          [
            new HTMLColumn(cssattributes,null,value) 
          ] as HTMLColumn[]));
    

    Note

    • The first new HTMLColumn represent the name of column and new HTMLColumn is the value
    • It is mandatory to cast the content to HTMLColumn
    • cssAttributes represents the ccs styles applied

Charts: Charts are an HTML element that allow you to visualize data using pie, line, or column graphs. These charts are created from the data stored in a data table, so it's essential to create the table first.

def dataTable = new DataTable([DataType.STRING, DataType.NUMBER ] as DataType[], ["COLUMN1", "COLUMN2"] as String[])

Note:
It is mandatory to cast the content to DataType

To add values to the datatable, the column correspond the name of the column and value is the number:

dataTable.addRow(["COLUMN", value] as String[])

Note
It is mandatory to cast the content to String

To create the chart, it is necessary use the GChartsFactory

def chartsFactory = new GChartsFactory(report)
def htmlDivPieChart = chartsFactory.createHTMLDivWrapperChart(ChartType.PIECHART, "divPieChart", name , dataTable);

Notes

  • It posible change the styles of htmlDivPieChart using : htmlDivPieChart.setStyle("cssStyle").
  • Is possible use types of chart: ChartType.PIECHART, ChartType.COLUMNCHART and ChartType.LINECHART.

Finally step is add the HMTL tag's to report and return it:

report.getComponents().add(HMTLTag)
return report

After choosing the HTML tag to display a text, you must query the inventory information to display. There are two ways to query the information: use Cypher to query directly in Ne4oj or use the Persistence API.

The Persistence API is extensive and contains many methods; however, the most commonly used ones are listed below.

MethodsDescriptionReturn
getAttributeValueAsString( classObject, IdObject, NameAttributes )Returns the value as string of an attributeString
getSpecialAttribute( classObject, IdObject , nameRelantionship )Returns relationship of given objectBusinessObjectLight
getObject​( classObject, IdObject )Returns the given objectBusinessObject
getParent( classObject, IdObject)Returns the object's parentBusinessObjectLight
getObjectChildren​( classObject, IdObject, -1)Returns the children of given objectBusinessObjectLight
getObjectsOfClassLight(classToFind, null, -1, -1)Returns all objects belong a classBusinessObjectLight

Note:

  • Business Object refers a object with all attributes meanwhile Business Object Light refers a object with only attributes: class name, object id and nam
  • If the object is a Business Object, it is possible to get any of its attributes:
object.getAttributes().get(attributeName)
  • If the object is a Business Object Light, only get the following attributes:
objectLight.getName()
objectLight.getClassName()
objectLight.getId()

Learning By Example

Case 1

Example showing in a table the cities in the inventory and to which state they belong

  1. Create the inventory report in the module of report as show in Figure 14

  2. Import the module

import org.neotropic.kuwaiba.modules.optional.reports.html.*
  1. Define the name and CSS style of report
def report = new HTMLReport("Cities in inventory" , "Neotropic SAS", "1.0")
report.setEmbeddedStyleSheet(HTMLReport.getDefaultStyleSheet())
  1. Use the method getObjectsOfClassLight to search the all cities in the Inventory and save in a variable
def cities = bem.getObjectsOfClassLight("City", null, -1, -1)
  1. Create the table with the column name
def citiesTable = new HTMLTable(null, null, ["City","State"] as String[])
  1. Go through all the cities in the array and query each one for her parent
cities.each { city -> 
    def state = bem.getParent( city.getClassName(), city.getId()))
  1. Add to table the data
citiesTable.getRows().add(new HTMLRow([
        new HTMLColumn( city.getName()),
        new HTMLColumn(counrty),
      
 
    ] as HTMLColumn[]))
}
  1. Add the table to report and return it
report.getComponents().add(citiesTable)
return report

9.The report must look like this

import org.neotropic.kuwaiba.modules.optional.reports.html.*

def report = new HTMLReport("City in inventory" , "Neotropic SAS", "1.0")
report.setEmbeddedStyleSheet(HTMLReport.getDefaultStyleSheet())

def cities = bem.getObjectsOfClassLight("City", null, -1, -1)
def citiesTable = new HTMLTable(null, null, ["City","State"] as String[])

cities.each { city -> 
    def state = bem.getParent( city.getClassName(), city.getId())

    citiesTable.getRows().add(new HTMLRow([
        new HTMLColumn( city.getName()),
        new HTMLColumn(state),
    ] as HTMLColumn[]))
}

report.getComponents().add(citiesTable)
return report
  1. The result of the report will be
reports by class
Figure 17. Report Result

Case 2

For this example, a title is added to case 1

  1. Create a message
def title = new HTMLMessage("color:black; font-weight: normal; font-size: 2em; ", null, String.format("Cities in Inventory"))

Note

In this case the css style are set as string

  1. Create a div containing the title
def divTitle = new HTMLDiv("div",title)

Note

It is possible to set css styles to the div,

divTitle.setStyle("width: 100vw;display: flex; justify-content: center; align-items: center;padding:4px")
  1. Add div to report
report.getComponents().add(divTitle)
  1. The report must look like this

import org.neotropic.kuwaiba.modules.optional.reports.html.*

def report = new HTMLReport("Cities in Inventory" , "Neotropic SAS", "1.0")
report.setEmbeddedStyleSheet(HTMLReport.getDefaultStyleSheet())

def cities = bem.getObjectsOfClassLight("City", null, -1, -1)
def citiesTable = new HTMLTable(null, null, ["City","State"] as String[])

cities.each { city -> 
    def state = bem.getParent( city.getClassName(), city.getId())

    citiesTable.getRows().add(new HTMLRow([
        new HTMLColumn( city.getName()),
        new HTMLColumn(state),
    ] as HTMLColumn[]))
}
def title = new HTMLMessage("color:black; font-weight: normal; font-size: 2em; ", null, String.format("Cities in Inventory"))
def divTitle = new HTMLDiv("div",title)
divTitle.setStyle("width: 100vw;display: flex; justify-content: center; align-items: center;padding:4px")

report.getComponents().add(divTitle)
report.getComponents().add(citiesTable)
return report
  1. The result of the report will be
reports by class
Figure 18. Title Report Result

Case 3

For this case, a bar chart is added to case 2 where the number of cities per state is displayed.

  1. Add the imports
import org.neotropic.kuwaiba.modules.optional.reports.javascript.DataTable
import org.neotropic.kuwaiba.modules.optional.reports.javascript.DataTable.DataType
import org.neotropic.kuwaiba.modules.optional.reports.plugins.gcharts.GChartsFactory
import org.neotropic.kuwaiba.modules.optional.reports.plugins.gcharts.GChartsFactory.ChartType
  1. Create the dataTable
def dataTable = new DataTable([DataType.STRING, DataType.NUMBER ] as DataType[], ["State", "Cities Number"] as String[])
  1. Define the variables where the number of cities per state is stored
def quindio = 0
def antioquia = 0
def valleCauca = 0
def cundinamarca = 0
  1. Implement the logic to check how many cities there are per state
 switch(state.getName()) {
        case "Antioquia":
            antioquia++
            break
        case "Quindío":
            quindio++
            break
        case "Cundinamarca":
            cundinamarca++
            break
         case "Valle del Cauca":
            valleCauca++
            break
        default:
            break
    }
  1. Add the value rows to dataTable
dataTable.addRow(["Antioquia",antioquia] as String[]) 
dataTable.addRow(["Quindio",quindio] as String[]) 
dataTable.addRow(["Cundinamarca",cundinamarca] as String[]) 
dataTable.addRow(["Valle del Cauca",valleCauca] as String[]) 
  1. Create the chartsFactory
def chartsFactory = new GChartsFactory(report)
  1. Generate the bar chart
def htmlDivColumnChart = chartsFactory.createHTMLDivWrapperChart(ChartType.COLUMNCHART, "divColumnChart", "Bar Chart Cities Per State", dataTable);
  1. Add the chart to report
report.getComponents().add(htmlDivColumnChart)
  1. The final code is

import org.neotropic.kuwaiba.modules.optional.reports.html.*
import org.neotropic.kuwaiba.modules.optional.reports.javascript.DataTable
import org.neotropic.kuwaiba.modules.optional.reports.javascript.DataTable.DataType
import org.neotropic.kuwaiba.modules.optional.reports.plugins.gcharts.GChartsFactory
import org.neotropic.kuwaiba.modules.optional.reports.plugins.gcharts.GChartsFactory.ChartType;

def report = new HTMLReport("Cities in Inventory" , "Neotropic SAS", "1.0")
report.setEmbeddedStyleSheet(HTMLReport.getDefaultStyleSheet())

def cities = bem.getObjectsOfClassLight("City", null, -1, -1)
def citiesTable = new HTMLTable(null, null, ["City", "State"] as String[])

def dataTable = new DataTable([DataType.STRING, DataType.NUMBER ] as DataType[], ["State", "Cities Number"] as String[])

def quindio = 0
def antioquia = 0
def valleCauca = 0
def cundinamarca = 0

cities.each { city -> 
    def state = bem.getParent( city.getClassName(), city.getId())

    switch(state.getName()) {
        case "Antioquia":
            antioquia++
            break
        case "Quindío":
            quindio++
            break
        case "Cundinamarca":
            cundinamarca++
            break
         case "Valle del Cauca":
            valleCauca++
            break
        default:
            break
    }


    citiesTable.getRows().add(new HTMLRow([
        new HTMLColumn( city.getName()),
        new HTMLColumn(state),
    ] as HTMLColumn[]))
}

dataTable.addRow(["Antioquia", antioquia] as String[]) 
dataTable.addRow(["Quindio", quindio] as String[]) 
dataTable.addRow(["Cundinamarca", cundinamarca] as String[]) 
dataTable.addRow(["Valle del Cauca", valleCauca] as String[]) 

def chartsFactory = new GChartsFactory(report)
def htmlDivColumnChart = chartsFactory.createHTMLDivWrapperChart(ChartType.COLUMNCHART, "divColumnChart", "Bar chart Cities Per State", dataTable);

def title = new HTMLMessage("color:black; font-weight: normal; font-size: 2em; ", null, String.format("Cities in Inventory"))
def divTitle = new HTMLDiv("div",title)
divTitle.setStyle("width: 100vw;display: flex; justify-content: center; align-items: center;padding:4px")

report.getComponents().add(divTitle)
report.getComponents().add(citiesTable)
report.getComponents().add(htmlDivColumnChart)



return report
  1. The result is
reports by class
Figure 19. Report With Column Chart