Lorem ipsum dolor sit amet:

24h / 365days

We offer support for our customers

Mon - Fri 8:00am - 5:00pm (GMT +1)

Get in touch

Cybersteel Inc.
376-293 City Road, Suite 600
San Francisco, CA 94102

Have any questions?
+44 1234 567 890

Drop us a line

About us

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec.

Chapter 9. Extending the Client

9. Extending the Client

In this chapter we consider various ways to extend the client side of ReportServer. Some of these extensions will be configured via configuration files and which allow, for example, to add further information tabs to the TeamView or add further links to the module bar. Other extensions need scripting. These include adding additional report exporters, displaying messages on login, or adding custom information to the status bar.

9.1. UrlView - Incorporating Websites and More

Via the configuration file /etc/ui/ you can add links and tabs to various locations within ReportServer. For example, you can add a new link to the module bar and specify to which URL it should point. Additionally you can restrict what you want to add to certain users or groups. A typical configuration file could like

<?xml version="1.0" encoding="UTF-8"?>
	   <!-- View Configuration -->
	   <!-- View Configuration -->
	   <!-- View Configuration -->
	   <!-- View Configuration -->

The three scopes (adminviews, objectinfo and module) allow you to add additional information tabs to objects in the administration module (for example, add an additional tab to a user object displaying information on that particular user), additional tabs to objects in the teamspace and within module you can add additional links to the module bar. The documentation report within teamspaces is by default, for example, integrated via the an objectinfo view configuration.

View configurations all share the following configuration

 <restrictTo><!-- can be used to restrict this to specific users/groups--></restrictTo>
 <name>The display name</name>

Via restrictTo you can specify users by username or groups or OUs (organizational units, i.e., folders in the user tree) via IDs to include this view only for users that match one of the restrictions. The name is the name to be displayed on the tab or in the module bar. The URL denotes the URL to be loaded.

Restrictions are specified in the following form


For adminviews and objectinfo views you can further restrict the view to specific object types. This is done by adding a "types" tag which takes a comma separated list of fully qualified names of objects for which this view applies. For example the following restriction would restrict the (objectinfo) view to report objects within the teamspace.


The following types are available for objectinfo views

  • {} All Objects in a Teamspace.
  • {} All folders in a Teamspace.
  • {} All reports and variants in a Teamspace.
  • {} All "exported reports" which were, for example, created by the scheduler.

The following types are available for adminviews

Objects in Report Management.


Type Description
AbstractReportManagerNodeDto All objects in the report management tree.
ReportDto reports
ReportFolderDto folders
Objects in User Management.


Type Description
AbstractUserManagerNodeDto All objects in the user management tree.
UserDto users
GroupDto groups
OrganisationalUnitDto organisational units (folders)
Objects in the file server.


Type Description
AbstractFileServerNodeDto All objects in the file server.
FileServerFolderDto folders
FileServerFileDto files
Objects in Datasource Management


Type Description
AbstractDatasourceManagerNodeDto All objects in datasource management.
DatasourceFolderDto folders
DatasourceDefinitionDto datasources
Objects in Dadget Management


Type Description
AbstractDashboardManagerNodeDto All objects in the dashboard tree
DashboardNodeDto dashboards
DashboardFolderDto folders

You can use replacements within the URL to generate dynamic URLs. The following replacements are available

  • ${username} Is replaced by the current user's username.
  • ${type} Is replaced by the class name of the corresponding object. This replacement is only available for objectinfo and adminviews.
  • ${id} Is replaced by the ID of the corresponding object. This replacement is only available for objectinfo and adminviews.
  • ${reportId} Report objects within a team space are always references. Thus, the replacement ${id} maps to the id of the reference rather than to the id of the actual report. In order to use the actual report's id you can use the replacement ${reportId}

9.1.1. ReportServer Specific URLs

Besides specifying a view via a URL ReportServer you can tell ReportServer to display the preview view of a report. For this, you need to define the URL as


where ID should be replaced by the id of the corresponding report or, for example, by the replacement ${reportId} when defining this view for report objects in the TeamSpace.

Note that, as with any configuration file you need to run config reload on the terminal for changes to take effect. Furthermore you need to reload your browser to see effects as the configuration is loaded onto the client on login.

9.2. CommandResult - A Script's Result

We will now get back to ReportServer scripts and have a closer look at the object returned by a script. In theory, you can return any object from a script. For example the script

"Hello World"

returns an object of type String. In order to transport the result onto the client the terminal process wraps such a result in an object of type CommandResult (located in package which the client knows how to handle. If executed in the terminal the terminal will extract the string and display

reportserver$ exec hello.groovy
Hello World

This is done dynamically behind the scenes. But, you can also make this explicit and directly return a CommandResult. For this, you need to change the script to

new CommandResult("Hello World")

When executing this script the result is identical to before. However, making the CommandResult explicit will give us more control over how the client treats the result. In Chapter 3. we have already seen how to add hyperlinks and anchors to CommandResults. You can furthermore add simple lists, tables and strings to structure the output on the terminal. Consider the following script


def result = new CommandResult()

return result

Executing this script produces the following output

reportserver$ exec hello.groovy

Besides lists and tables, you can also directly return HTML.


def result = new CommandResult()
result.addResultHtml('<b>Hello</b> World')

return result

These techniques, however, are limited to format the results of a script when displayed on a terminal. The CommandResult object, on the other hand, is not limited to terminal formatting. A CommandResult object can contain one or more objects of type CommandResultExtensions which trigger certain responses on the client. For example, this allows you to display popup messages or execute arbitrary JavaScript code.

9.2.1. Displaying Messages

In order to display popup messages your script needs to add a CommandResultExtension of type CreMessage to the CommandResult object. Following is a simple example.


def result = new CommandResult()

def msg = new CreMessage("Hello World")

return result

You can further control the size of the window and also directly add HTML.


def result = new CommandResult()

def msg = new CreMessage()
msg.setHtml("<b>Hello World</b>")

return result

9.2.2. Executing Custom JavaScript

The CreJavaScript CommandResultObject allows to specify custom JavaScript which is executed on the client.


def result = new CommandResult()

def script = """
alert("Hello World");

result.addExtension(new CreJavaScript(script))

return result

9.3. ClientExtensionService

So far we have seen how to customize the output within the terminal, how to display messages in popups or execute custom JavaScript. In this section we will look at the so-called ClientExtensionService that can be accessed via the GLOBALS object. The ClientExtensionService offers methods to insert entries to various toolbars and context menus. Each new entry comes with a callback, that is, a ReportServer script that is executed when the specified entry is activated. Depending on where you added the entry your script is provided with additional information. For example, when adding an entry to the context menu in the report management view in the admin module, your script will get the id of the corresponding report object as an argument.

One thing to keep in mind when using the ClientExtensionService is that all effects are only valid as long as the current page is not refreshed. In order to install the changes permanently you should thus add the script into the onlogin.d folder.

The ClientExtensionService currently offers the following methods.

addStatusBarLabel() Allows to display info texts in the status bar.
addMenuEntry() Allows to add entries to certain context menus.
addToolbarEntry() Allows to add buttons to certain toolbars.
addReportExportOutputFormat() Allows to create custom exporters. We discuss this in detail in Chapter 12.

9.3.1. Adding Information to the Status Bar

The first method (addStatusBarLabel) allows you to add simple info texts to the status bar. The concept is best explained by a small example.

def service =['clientExtensionService']

service.addStatusBarLabel("All is fine")

As you might have guessed, the first line obtains the ClientExtensionService from the GLOBALs object. All that is left to do is to set a status update. Besides just adding text you can also call

addStatusBarLabel("All is fine", "path to some icon", true)

where the second parameter should point to an icon and the third parameter controls whether the object is added to the left or to the right (default).

You can of course access all server objects and methods within this script. E.g., the following executes a given dynamic list and prints the report name and its number of records into the status bar.


ReportService reportService = GLOBALS.getRsService(ReportService.class)
ReportExecutorService reportExec = GLOBALS.getRsService(ReportExecutorService.class)

TableReportVariant report = reportService.getReportById(2078898)

String reportName = report.getName()

RSTableModel reportCompiled = (RSTableModel) reportExec.execute(report, "RS_TABLE", ReportExecutionConfig.EMPTY_CONFIG)

int rowCount = reportCompiled.getRowCount()

/* prepare output */
def ces =
ces.addStatusBarLabel("Info: ${reportName} - ${rowCount} rows")

9.3.2. Adding Context Menu Entries

The ClientExtensionService allows you to add menu entries to the following context menus

Module Description Menu Name
Datasource Manager The datasource manager within the admin module datasource:admin:tree:menu
Report Manager The report manager within the admin module reportmanager:admin:tree:menu
File Server The file server within the admin module fileserver:admin:tree:menu
Dashboard Library The dashboard library within the admin module dashboard:admin:tree:menu
User Manager The user manager within the admin module usermanager:admin:tree:menu

To add an entry to a specific menu you need to access the menu by name (we give the menu names in the above table, for example, usermanager:admin:tree:menu corresponds to the context menu within the user manager tree).

The simplest way to add a menu entry is to simply call the method addMenuEntry() from the ClientExtensionService:

public void addMenuEntry(String menuName, String entryName, String scriptLocation, String configArgument)

The method takes the menu name, a name for the entry, a location of the script that is to be called when the entry is activated, and an argument given to the script. In the following we want to add a menu to the user tree. We call our script that generates the entry adddisplayinfoentry.groovy.

def service =['clientExtensionService']

service.addMenuEntry("usermanager:admin:tree:menu", "display info", "fileserver/bin/extensions/menu/displayuserinfo.groovy", "an argument")
The script must be executed before the user tree is loaded for the first time.
If you execute the above script and navigate to the user manager in the administration module and right click on any item in the tree you will see the new entry.
display info

If you activate the entry you will see an error message, since we haven't yet created a script at location


We are now going to create this file and use the above and display a simple message outputting the object's id.


def result = new CommandResult()

def msg = new CreMessage("ID: " + context['id'] + ", args" + args)

return result
The important part here is the context object which contains a field id corresponding to the id of the object clicked upon. Besides the id, the context also contains
id The object's id.
classname The object's classname.
path The object's path.
Display Conditions

Sometimes it might be inconvenient to add the menu entry to every object in the tree. That is, maybe we want to add an entry only to user objects, but not to groups or organizational units. To have full control over how the menu item is created you can directly create an object of type AddMenuEntryExtension located in package To better control when the entry is displayed, use DisplayConditions (located in the same package).


def service =['clientExtensionService']

def entry = new AddMenuEntryExtension()
entry.setLabel("display info")

def cond = new DisplayCondition("classname", "")


Note that the for menus you can currently only compare classnames. Also note that always the base class of the DTO is used, that is, instead of UserDtoDec you need to use UserDto.

9.3.3. Adding Toolbar Entries

Besides adding entries to context menus, you can add buttons to various toolbars, including all toolbars within the various admin modules. The mechanism is similar to the mechanism we described above. The following toolbars support the addition of custom buttons:

Module Description Menu Name
Datasource Manager The datasource manager within the admin module datasource:admin:view:toolbar
Report Manager The report manager within the admin module reportmanager:admin:view:toolbar
File Server The file server within the admin module fileserver:admin:view:toolbar
Dashboard Library The dashboard library within the admin module dashboard:admin:view:toolbar
User Manager The user manager within the admin module usermanager:admin:view:toolbar
Report Executor The report executor module. This includes the report execution by URL. reportexecutor:main:toolbar
Scheduler Job List The scheduler job list module. schedulerlist:main:toolbar

Similar as above you can either use helper methods within the ClientExtensionService such as

public void addToolbarEntry(String toolbarName, String entryName, String entryIcon, String scriptLocation, String arguments){

or alternatively create an object of type AddToolbarEntryExtension, also located in the package


def service =['clientExtensionService']

def entry = new AddToolbarEntryExtension()
entry.setLabel("display info")

def cond = new DisplayCondition("classname", "")


Note that with toolbar buttons you have more control over when buttons are to be displayed, as you can specify the exact type, that is, TableReportVariantDto instead of ReportVariantDto. This, for example, allows you to add a custom button only to dynamic lists, but not to jasper reports.

9.3.4. Future Additions

The possibilities offered by the ClientExtensionService are still rudimentary. We plan to extend these in future versions and are keen to hear your thoughts on what you would like to be able to do and what you are currently missing.

InfoFabrik GmbH

Wir wollen, dass alle Unternehmen, Institutionen und Organisationen, die Daten auswerten, selbständig und zeitnah genau die Informationen erhalten, die sie für ein erfolgreiches Arbeiten benötigen.

InfoFabrik GmbH
Klingholzstr. 7
65189 Wiesbaden

+49 (0) 611 580 66 25

Kontaktieren Sie uns

Bitte addieren Sie 8 und 6.
Copyright 2007 - 2024 InfoFabrik GmbH. All Rights Reserved.

Auf unserer Website setzen wir Cookies und andere Technologien ein. Während einige davon essenziell sind, dienen andere dazu, die Website zu verbessern und den Erfolg unserer Kampagnen zu bewerten. Bei der Nutzung unserer Website werden Daten verarbeitet, um Anzeigen und Inhalte zu messen. Weitere Informationen dazu finden Sie in unserer Datenschutzerklärung. Sie haben jederzeit die Möglichkeit, Ihre Einstellungen anzupassen oder zu widerrufen.

Datenschutzerklärung Impressum
You are using an outdated browser. The website may not be displayed correctly. Close