The tools subapp is a special type of subapp which contains a list of tools. A tool is a small functional block which is defined by a 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolDefinition
 and is rendered as a subtab of the subapp.

Tools provide you with UI elements, basically forms, for working with configuration and content. You can use the form fields to enter and edit values and save them or trigger other actions. It also provides the ability to validate the form input thereby helping users enter correct data and reducing errors.

You can create a tool with a few lines of YAML configuration and at least one custom Java class. This reduces effort compared to creating a completely custom app 

Tool usage examples: 

  • Modify your module's configuration such as setting SMTP settings for a Mail module.
  • Query or report the usage of content items. 
  • Configure a connector to an external system.
  • Start batch processes and execute complex commands that may require user input.

In this example, the tools subapp lets you query groups and permissions associated to a given user:

The tool definition class is i18n-ized and comes with its own key generator class 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolDefinitionKeyGenerator
.

ToolsSubApp definition

subApps:
  main: 
    class: info.magnolia.ui.framework.tools.ToolsSubAppDescriptor
    subAppClass: info.magnolia.ui.framework.tools.ToolsSubApp
    tools:
Node nameValue

 
subApps

 

 
class

info.magnolia.ui.framework.tools.ToolsSubAppDescriptor

 
subAppClass

info.magnolia.ui.framework.tools.ToolsSubApp

 
tools

 

<subapp name>

required

Subapp node name. This is the internal ID of the subapp. In this example it is main.

class

required

For a tools subapp must be info.magnolia.ui.framework.tools.ToolsSubAppDescriptor or a subclass.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolsSubAppDescriptor
defines a subapp with several tools.

subAppClass

required

For a tools subapp must be info.magnolia.ui.framework.tools.ToolsSubApp or a subclass.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolsSubApp
implements a subapp with several tools.

   tools

required

Map of ToolDefinition.

Tools are defined by 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolDefinition
.

(See below for more details concerning tool definition.)

Example of an app with a tools subapp

Here is a complete example of a YAML based app which contains a tools subapp.

 <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Log in - Magnolia Bitbucket</title><script>
window.WRM=window.WRM||{};window.WRM._unparsedData=window.WRM._unparsedData||{};window.WRM._unparsedErrors=window.WRM._unparsedErrors||{};
WRM._unparsedData["com.atlassian.bitbucket.server.bitbucket-webpack-INTERNAL:user-keyboard-shortcuts-enabled.data"]="true";
WRM._unparsedData["com.atlassian.analytics.analytics-client:programmatic-analytics-init.programmatic-analytics-data-provider"]="false";
WRM._unparsedData["com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path.context-path"]="\u0022\u0022";
WRM._unparsedData["com.atlassian.plugins.atlassian-clientside-extensions-runtime:runtime.atlassianDevMode"]="false";
WRM._unparsedData["com.atlassian.bitbucket.server.bitbucket-webpack-INTERNAL:date-format-preference.data"]="\u0022\u0022";
WRM._unparsedData["com.atlassian.bitbucket.server.feature-wrm-data:bitbucket.global.theme.data"]="false";
WRM._unparsedData["com.atlassian.analytics.analytics-client:policy-update-init.policy-update-data-provider"]="false";
WRM._unparsedData["com.atlassian.bitbucket.plugins.bitbucket-slack-server-integration-plugin:slack-link-error-resources.slack-link-error"]="{}";
WRM._unparsedData["com.atlassian.bitbucket.server.feature-wrm-data:user.time.zone.onboarding.data"]="true";
if(window.WRM._dataArrived)window.WRM._dataArrived();</script>
<link rel="stylesheet" href="/s/c2e7fb6cb0fa3d99cfd1ed5573a5b732-CDN/1015515914/fdb5904/1h5ouvp/a93e8b54a53a5453c42e8c7cfb35551a/_/download/contextbatch/css/_super/batch.css" data-wrm-key="_super" data-wrm-batch-type="context" media="all">
<link rel="stylesheet" href="/s/c3b4ddaba8d3dce9466950696444d252-CDN/1015515914/fdb5904/1h5ouvp/80af30e6da65e29f7038393c9f70794e/_/download/contextbatch/css/bitbucket.page.login,-_super/batch.css" data-wrm-key="bitbucket.page.login,-_super" data-wrm-batch-type="context" media="all">
<link rel="stylesheet" href="/s/a5886b3e3e45b4adb9b9991e2cf18803-CDN/1015515914/fdb5904/1h5ouvp/f4992ec124d5384cd0091fae42c3ca97/_/download/contextbatch/css/bitbucket.layout.focused,bitbucket.layout.base,atl.general,bitbucket.internal.feature.theme,-_super/batch.css?slack-enabled=true" data-wrm-key="bitbucket.layout.focused,bitbucket.layout.base,atl.general,bitbucket.internal.feature.theme,-_super" data-wrm-batch-type="context" media="all">
<script src="/s/2fb1765c7438a1e383facff8dd19270a-CDN/1015515914/fdb5904/1h5ouvp/a93e8b54a53a5453c42e8c7cfb35551a/_/download/contextbatch/js/_super/batch.js?locale=en-US" data-wrm-key="_super" data-wrm-batch-type="context" data-initially-rendered></script>
<script src="/s/8fd0897a356f9fee979922482537ec9e-CDN/1015515914/fdb5904/1h5ouvp/80af30e6da65e29f7038393c9f70794e/_/download/contextbatch/js/bitbucket.page.login,-_super/batch.js?locale=en-US" data-wrm-key="bitbucket.page.login,-_super" data-wrm-batch-type="context" data-initially-rendered></script>
<script src="/s/b26a251d5dcc697b8b37326544044035-CDN/1015515914/fdb5904/1h5ouvp/f4992ec124d5384cd0091fae42c3ca97/_/download/contextbatch/js/bitbucket.layout.focused,bitbucket.layout.base,atl.general,bitbucket.internal.feature.theme,-_super/batch.js?locale=en-US&amp;slack-enabled=true" data-wrm-key="bitbucket.layout.focused,bitbucket.layout.base,atl.general,bitbucket.internal.feature.theme,-_super" data-wrm-batch-type="context" data-initially-rendered></script>
<meta name="application-name" content="Bitbucket"><link rel="shortcut icon" type="image/x-icon" href="/s/1015515914/fdb5904/1h5ouvp/1.0/_/download/resources/com.atlassian.bitbucket.server.bitbucket-webpack-INTERNAL:favicon/favicon.ico" /><link rel="search" href="https://git.magnolia-cms.com/plugins/servlet/opensearch-descriptor" type="application/opensearchdescription+xml" title="Bitbucket code search"/></head><body class="aui-page-focused aui-page-focused-small aui-page-size-small bitbucket-theme user-login"><script type="text/javascript">require('@bitbucket/internal/feature/theme').init();</script><ul id="assistive-skip-links" class="assistive"><li><a href="#content">Skip to content</a></li></ul><div id="page"><!-- start #header --><header id="header" role="banner"><section class="notifications"></section><nav class="aui-header aui-dropdown2-trigger-group" aria-label="site"><div class="aui-header-inner"><div class="aui-header-before"><button class=" aui-dropdown2-trigger app-switcher-trigger aui-dropdown2-trigger-arrowless" aria-controls="app-switcher" aria-haspopup="true" role="button" data-aui-trigger href="#app-switcher"><span class="aui-icon aui-icon-small aui-iconfont-appswitcher">Linked Applications</span></button><div id="app-switcher" class="aui-dropdown2 aui-style-default" role="menu" hidden data-is-user-admin="false" data-is-switcher="true"><div class="app-switcher-loading">Loading&hellip;</div></div></div><div class="aui-header-primary"><span id="logo" class="aui-header-logo bitbucket-header-logo"><a href="https://git.magnolia-cms.com"><img src="/s/1015515914/fdb5904/1h5ouvp/1.0/_/download/resources/com.atlassian.bitbucket.server.bitbucket-webpack-INTERNAL:bitbucket-logo/images/logo/bitbucket.svg" alt="Bitbucket"/></a></span><ul class="aui-nav"></ul></div><div class="aui-header-secondary"><ul class="aui-nav"><li class=" help-link"title="Help"><a class=" aui-dropdown2-trigger aui-dropdown2-trigger-arrowless" aria-controls="com.atlassian.bitbucket.server.bitbucket-server-web-fragments-help-menu" aria-haspopup="true" role="button" tabindex="0" data-aui-trigger><span class="aui-icon aui-icon-small aui-icon-small aui-iconfont-question-filled">Help</span></a><div id="com.atlassian.bitbucket.server.bitbucket-server-web-fragments-help-menu" class="aui-dropdown2 aui-style-default" role="menu" hidden data-aui-dom-container="body"><div class="aui-dropdown2-section help-items-section"><ul class="aui-list-truncate" role="presentation"><li role="presentation"><a href="https://docs.atlassian.com/bitbucketserver/docs-0814/Bitbucket+Data+Center+and+Server+documentation?utm_campaign=in-app-help&amp;amp;utm_medium=in-app-help&amp;amp;utm_source=stash" title="Go to the online documentation for Bitbucket" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:general-help">Online help</a></li><li role="presentation"><a href="https://www.atlassian.com/git?utm_campaign=learn-git&amp;utm_medium=in-app-help&amp;utm_source=stash" title="Learn about Git commands &amp; workflows" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:learn-git">Learn Git</a></li><li role="presentation"><a href="/getting-started"class="getting-started-page-link" title="Overview of Bitbucket features" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:getting-started-page-help-link">Welcome to Bitbucket</a></li><li role="presentation"><a href="/#"class="keyboard-shortcut-link" title="Discover keyboard shortcuts in Bitbucket" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:keyboard-shortcuts-help-link">Keyboard shortcuts</a></li><li role="presentation"><a href="https://go.atlassian.com/bitbucket-server-whats-new?utm_campaign=in-app-help&amp;utm_medium=in-app-help&amp;utm_source=stash" title="Learn about what&#39;s new in Bitbucket" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:whats-new-link">What&#39;s new</a></li><li role="presentation"><a href="https://go.atlassian.com/bitbucket-server-community?utm_campaign=in-app-help&amp;utm_medium=in-app-help&amp;utm_source=stash" title="Explore the Atlassian community" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:community-link">Community</a></li><li role="presentation"><a href="/about" title="About Bitbucket" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:about">About</a></li></ul></div></div></li><li class=" alerts-menu"title="View system alerts"><a href="#alerts" id="alerts-trigger"class="alerts-menu" title="View system alerts" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:global-alerts-menu-item">Alerts</a></li></ul></div></div> <!-- End .aui-header-inner --></nav> <!-- End .aui-header --></header><!-- End #header --><!-- Start #content --><section id="content" role="main" tabindex="-1" data-timezone="-120" ><div class="aui-page-panel content-body" ><div class="aui-page-panel-inner"><main role="main" id="main" class="aui-page-panel-content" ><h2>Log in</h2><form class="aui top-label prevent-double-submit " action="/j_atl_security_check" method="post" accept-charset="UTF-8"><div class="field-group"><label for="j_username" >Username</label><input class="text long-field" type="text" id="j_username"  name="j_username"  autofocus accesskey="u"/></div><div class="field-group"><label for="j_password" >Password</label><input class="text long-field" type="password" id="j_password"  name="j_password"  accesskey="p"/></div><div class="aui-group"><fieldset class="group checkbox"><div class="checkbox"><input class="checkbox" type="checkbox" id="_atl_remember_me"  name="_atl_remember_me"  checked="checked"  accesskey="r"/><label for="_atl_remember_me" >Keep me logged in</label></div></fieldset></div><div class="aui-group"><input name="next" type="hidden" value="/projects/DOCUMENTATION/repos/toolssubapp-example/raw/src/main/resources/toolssubapp-example/apps/hello-tools-app.yaml?at=master"/><input name="queryString" type="hidden" value="next=%2Fprojects%2FDOCUMENTATION%2Frepos%2Ftoolssubapp-example%2Fraw%2Fsrc%2Fmain%2Fresources%2Ftoolssubapp-example%2Fapps%2Fhello-tools-app.yaml%3Fat%3Dmaster"/><input class="aui-button aui-button-primary" type="submit" id="submit"  name="submit"  value="Log in" accesskey="s"/><a id="forgot" class="aui-button aui-button-link"  name="forgot" href="/passwordreset" autocomplete="off" tabindex="0">Unable to access your account?</a></div></form></main></div></div></section><!-- End #content --><!-- Start #footer --><footer id="footer" role="contentinfo"><section class="notifications"></section><section class="footer-body"><ul><li data-key="footer.license.free.eval">Git repository management powered by a free <a href="https://www.atlassian.com/software/bitbucket/">Atlassian Bitbucket</a> evaluation license</li></ul><ul><li>Atlassian Bitbucket <span title="fdb5904e84ca72e8d62953007cf5cf6cfcdfebd8" id="product-version" data-commitid="fdb5904e84ca72e8d62953007cf5cf6cfcdfebd8" data-system-build-number="fdb5904"> v8.14.0</span></li><li data-key="footer.links.documentation"><a href="https://docs.atlassian.com/bitbucketserver/docs-0814/Bitbucket+Data+Center+and+Server+documentation?utm_campaign=in-app-help&amp;utm_medium=in-app-help&amp;utm_source=stash" target="_blank">Documentation</a></li><li data-key="footer.links.jac"><a href="https://jira.atlassian.com/browse/BSERV?utm_campaign=in-app-help&amp;utm_medium=in-app-help&amp;utm_source=stash" target="_blank">Request a feature</a></li><li data-key="footer.links.about"><a href="/about">About</a></li><li data-key="footer.links.contact.atlassian"><a href="https://www.atlassian.com/company/contact?utm_campaign=in-app-help&amp;utm_medium=in-app-help&amp;utm_source=stash" target="_blank">Contact Atlassian</a></li></ul><div id="footer-logo"><a href="https://www.atlassian.com/" target="_blank">Atlassian</a></div></section></footer><!-- End #footer --></div><script>require('bitbucket/internal/layout/base/base').onReady(null, "Magnolia Bitbucket" ); require('bitbucket/internal/widget/keyboard-shortcuts/keyboard-shortcuts').onReady();</script><script type="text/javascript">require('bitbucket/internal/page/login/login').onReady();</script></body></html>

Node nameValue

 
hello-tools-app

-

 
appClass

info.magnolia.ui.framework.app.BaseApp

 
label

Sample Tools

 
icon

icon-development-app

 
name

hello-tools-app

 
subApps

 -

 
main

 -

 
class

info.magnolia.ui.framework.tools.ToolsSubAppDescriptor

 
subAppClass

info.magnolia.ui.framework.tools.ToolsSubApp

 
tools

-

 
dashboard

 -

 
presenterClass

info.magnolia.documentation.apps.toolssubapp.presenters.DashboardToolPresenter

 
i18n

 -

 
class

info.magnolia.ui.framework.tools.FormToolDefinition

 
actions

-

 
helloworld

 -

 
class

info.magnolia.ui.framework.tools.FormToolDefinition

 
presenterClass

info.magnolia.documentation.apps.toolssubapp.presenters.HelloWorldPresenter

 
description

This is the hello world example for configured tools

 
form

-

 
actions

-

Note that this example requires Java 1.8 to run. You can download the .jar file here: 

Error rendering macro 'artifact-resource-macro'

com.sun.jersey.api.client.ClientHandlerException: java.net.NoRouteToHostException: No route to host (Host unreachable)

. See Installing a module for help.

Properties:

<subapp name>

required

Subapp node name. This is the internal ID of the subapp. In this example it is main.

class

required

For a tools subapp must be info.magnolia.ui.framework.tools.ToolsSubAppDescriptor or a subclass.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolsSubAppDescriptor
defines a subapp with several tools.

subAppClass

required

For a tools subapp must be info.magnolia.ui.framework.tools.ToolsSubApp or a subclass.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolsSubApp
implements a subapp with several tools.

   tools

required

Map of ToolDefinition.

Tools are defined by 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolDefinition
(where you may have to define the presenter class that implements ToolPresenter).

name

required

Name of the tool. In this example, there are three tools named dashboard, i18n and helloworld.

class

optional, default is info.magnolia.ui.framework.tools.ToolDefinition

presenterClass

required

Must implement 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolPresenter
.

This example displays as follows in the Magnolia interface:

Tool definition

A tool is a small functional block which exists within a tools subapp. Tools subapps may have one or several tools.

Each tool is defined by a 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolDefinition
 in which you have to define the presenter class that must implement 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolPresenter
. The tool definition class is i18n-ized and comes with its own key generator class: 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ToolDefinitionKeyGenerator
.

Tools usually have some custom Java code to implement the logic of the task you want it to accomplish. The logic can be in a presenter class or in an action class depending on the type of the tool definition class.

Tool examples

Each tool defined in the tools subapp example above is different:

Dashboard tool

By using a custom presenter class (and View or ViewAdapter), you get the full freedom to build a Vaadin UI.

The dashboard tool uses the default configuration class (property class), and therefore must provide a presenterClass. This is the YAML excerpt for this tool definition from the example:This is the custom presenter:

Note:

  • The presenter implements #start which returns the View.
  • The method uses Lambda expression. This is why the example requires Java 8.

i18n tool

The i18n tool has the value info.magnolia.ui.framework.tools.FormToolDefinition set for the class property. 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") FormToolDefinition
(or actually its implementation 
$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") ConfiguredFormToolDefinition
) provides a default presenterClass.

By using FormToolDefinition, you can provide some action configurations only; no need to write presentation code. Implement the logic to execute on the custom action class.

FormToolDefinition also requires a list of action classes. This tool example provides one custom action: info.magnolia.documentation.apps.toolssubapp.actions.ReloadTranslationsAction.

Note:

  • You should inject the definition class in the constructor.
  • You can inject other components such as
    $webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") TranslationService
    and
    $webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") UiContext
    (lines 7-8).

Helloworld tool

Like i18n, the helloworld tool also has the value info.magnolia.ui.framework.tools.FormToolDefinition set for the class property. Like the dashboard tool, helloworld provides a custom presenterClass: info.magnolia.documentation.apps.toolssubapp.presenters.HelloWorldPresenter.

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") HelloWorldPresenter
extends info.magnolia.ui.framework.tools.FormToolPresenter (which is the default presenterClass for FormToolDefinition).

Other tool implementation examples

Magnolia provides the following implementations based on 

$webResourceManager.requireResource("info.magnolia.sys.confluence.artifact-info-plugin:javadoc-resource-macro-resources") FormToolPresenter
in the Security app that you can use for inspiration:

You typically have to implement your own presenterClass to fulfill your requirements. However, extending FormToolPresenter may be a good starting point.

 

 

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))