How to Add a Tool to the Right Toolbar in EzyPlatform Admin

Updated at 1788536746000
The EzyPlatform admin UI includes a fixed toolbar on the right side of the screen. This toolbar is used for quick tools such as dark mode, toolbar expand/collapse, and extra tools contributed by admin plugins.
For an admin plugin, the cleanest extension model is to separate the tool into two parts:
  • use a Thymeleaf fragment to add the visible item to the toolbar;
  • use static CSS/JavaScript files for complex behavior, UI state, API calls, modals, websocket logic, editors, or third-party libraries.
For a simple tool, most of the implementation can live in the fragment. For a complex tool, the fragment should usually be only a button or an anchor point, while the main logic lives in static files. This keeps the shared admin layout light and makes the tool easier to maintain, cache, debug, and bundle.

How it works

The shared admin layout renders fragments/right-toolbar. That fragment creates the toolbar container, renders the built-in items, then reads the view variable rightToolbarToolFragments. Each item in this list is the name of a Thymeleaf template fragment, rendered through its :: content region.
Near the end of the page, the admin layout also loads common scripts and optional plugin-provided scripts. A plugin can add CSS/JS assets to a view through variables such as additionalStyleFiles, moduleScriptFiles, finalScriptFiles, or additionalScripts.
The high-level flow looks like this:
flowchart TD
    A[Admin opens a page] --> B[Controller returns a View]
    B --> C[Platform and plugin ViewDecorators add view variables]
    C --> D[The ezyadmin layout is rendered]
    D --> E[Render fragments/right-toolbar]
    E --> F{rightToolbarToolFragments exists?}
    F -- Yes --> G[Render each tool fragment into the toolbar]
    F -- No --> H[Render only built-in tools]
    G --> I[Load additional CSS and JavaScript]
    H --> I
    I --> J[Tool initializes browser-side behavior]

Fragment or static files

Use a fragment when the tool only needs a small amount of HTML, such as a button that opens a page, a simple menu item, or an action that already delegates to shared JavaScript.
Prefer static files when the tool has any of these traits:
  • multiple UI states;
  • its own modal, panel, dropdown, or editor;
  • several API calls;
  • state stored in localStorage;
  • external JavaScript/CSS libraries;
  • code that should be easy to debug or bundle separately.
In practice, a good pattern is: the fragment adds the toolbar button, a static CSS file defines the tool-specific UI, and a static JavaScript file initializes behavior with $(document).ready(...) or a clearly named init function.

Suggested admin plugin structure

An admin plugin can organize its resources like this:
your-admin-plugin
├── module.properties
├── src/main/java
│   └── .../view/YourAdminViewDecorator.java
└── src/main/resources
    ├── messages/messages.properties
    ├── static/your-plugin/css/right-toolbar-tool.css
    ├── static/your-plugin/js/right-toolbar-tool.js
    └── templates/your-plugin/fragments/right-toolbar-tool.html
The roles are:
ComponentRole
right-toolbar-tool.htmlDeclares the item rendered into the toolbar
right-toolbar-tool.cssHolds styles owned by the tool
right-toolbar-tool.jsHandles click behavior, panels, API calls, and state
YourAdminViewDecoratorAdds the toolbar fragment and static files to the view model
messages.propertiesDeclares i18n keys used by the fragment
Use a folder name such as your-plugin to avoid template and static asset collisions with the platform or other plugins.

Create the toolbar fragment

For example, a "Quick Action" tool can define this fragment:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<th:block th:fragment="content">
    <a href="javascript:void(0)"
       class="right-toolbar-item"
       id="quickActionToolbarItem"
       th:title="#{quick_action}">
        <i class="fas fa-bolt"></i>
        <span>[[#{quick_action}]]</span>
    </a>
</th:block>
</body>
</html>
The fragment must provide a content region because the toolbar renders it as template-name :: content.
Keep this HTML small. If the tool needs a large panel, modal, or form, let this fragment contain only the opening button. The larger UI can be created by JavaScript or attached through another suitable extension point.

Register the fragment in the view

The plugin needs to add the fragment name to rightToolbarToolFragments. A common way to do this is with a ViewDecorator in the admin plugin.
Example:
package com.example.admin.view;

import com.tvd12.ezyfox.bean.annotation.EzySingleton;
import com.tvd12.ezyhttp.server.core.view.View;
import com.tvd12.ezyhttp.server.core.view.ViewDecorator;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@EzySingleton
public class QuickActionViewDecorator implements ViewDecorator {

    @Override
    public void decorate(HttpServletRequest request, View view) {
        addItem(view, "rightToolbarToolFragments", "your-plugin/fragments/right-toolbar-tool");
        addItem(view, "additionalMessageKeys", "quick_action");
    }

    @SuppressWarnings("unchecked")
    private void addItem(View view, String variableName, String value) {
        List<String> values = view.getVariable(variableName);
        if (values == null) {
            values = new ArrayList<>();
            view.setVariable(variableName, values);
        }
        if (!values.contains(value)) {
            values.add(value);
        }
    }
}
When the plugin is active, the admin plugin package is included in component scanning. The ViewDecorator becomes a bean, is called while views are rendered, and the fragment appears in the right toolbar.
The additionalMessageKeys line is important when the JavaScript file needs to read the label from ezyadmin.messages.quick_action. The toolbar fragment itself can resolve #{quick_action} directly during Thymeleaf rendering, but browser-side JavaScript only sees message keys that were added to the view and copied into ezyadmin.messages.

Load CSS and JavaScript from static files

For complex tools, place CSS/JS files under src/main/resources/static. The admin runtime enables static resources, so these files can be served as normal static assets.
Example files:
src/main/resources/static/your-plugin/css/right-toolbar-tool.css
src/main/resources/static/your-plugin/js/right-toolbar-tool.js
Then add them to the view:
@Override
public void decorate(HttpServletRequest request, View view) {
    addItem(view, "rightToolbarToolFragments", "your-plugin/fragments/right-toolbar-tool");
    addItem(view, "additionalMessageKeys", "quick_action");
    addItem(view, "additionalStyleFiles", "/your-plugin/css/right-toolbar-tool.css");
    addItem(view, "finalScriptFiles", "/your-plugin/js/right-toolbar-tool.js");
}
In the admin layout, additionalStyleFiles is loaded in the <head>, while finalScriptFiles is loaded near the end of the page, after the main scripts and fragment scripts. For a tool that depends on ezyadmin, jQuery, or shared helper functions, finalScriptFiles is usually the most convenient choice.
Use moduleScriptFiles when the file needs to be loaded earlier as a module-level script. Use additionalScripts only for short inline snippets; avoid it for long tool logic.

Write the tool JavaScript

A static JavaScript file should check whether the target toolbar item exists before binding events. This keeps the file safe even if a page does not render the tool.
(function() {
    function initQuickActionTool() {
        var $item = $('#quickActionToolbarItem');
        if (!$item.length) {
            return;
        }
        $item.on('click', function() {
            ezyadmin.showLoadingScreen();
            $.ajax({
                url: '/your-plugin/api/quick-action',
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify({})
            })
            .done(function() {
                ezyadmin.shortToast('bg-success', ezyadmin.messages.successfully);
            })
            .fail(function(e) {
                ezyadmin.processUpdateApiErrors(e);
            })
            .always(function() {
                ezyadmin.hideLoadingScreen();
            });
        });
    }

    $(document).ready(initQuickActionTool);
})();
Admin plugin controllers are commonly prefixed automatically with the plugin name when the controller URI is not already prefixed. Keeping API URLs under the plugin namespace avoids collisions with platform routes or routes from other plugins.

Add i18n labels

In the admin plugin's `messages/messages.properties`:
quick_action=Quick action
If the plugin provides additional language files, add the same key to each language file. The fragment should use #{quick_action} instead of hard-coded text so the toolbar works well in multilingual admin interfaces.

Design pattern for complex tools

For a small tool, a click handler can open a URL or call one simple API. For a larger tool, prefer this model:
flowchart LR
    A[Toolbar item] --> B[Static JS]
    B --> C[Dedicated panel or modal]
    B --> D[Plugin API controller]
    D --> E[Business service]
    B --> F[localStorage for UI state if needed]
    C --> B
Avoid putting all HTML, CSS, and JavaScript into one long fragment. Long fragments make the shared admin layout harder to reason about, reduce cache efficiency, and make versioning more awkward. Static files let the browser cache assets, make DevTools debugging easier, and allow the plugin to use a bundler or third-party libraries when needed.

Things to keep in mind

The rightToolbarToolFragments variable only adds items to the toolbar. It does not provide business logic by itself. If the tool needs to read or update data, create an API controller in the admin plugin and apply the same authentication and authorization approach used by other admin controllers.
The right toolbar has expanded and minimized states. A toolbar item should use the right-toolbar-item class, an icon inside an i element, and text inside a span element so it follows the built-in toolbar styling.
Use plugin-specific HTML IDs, such as yourPluginQuickActionToolbarItem, to avoid conflicts with built-in toolbar items or other plugins.
Place static assets under a plugin-specific folder such as /your-plugin/..., instead of directly under /js/tool.js or /css/tool.css.
If a static file changes in production but the browser still serves a cached copy, rename the file, add a version query parameter, or use the platform's resource versioning mechanism where appropriate.

Conclusion

To add a tool to the right toolbar in EzyPlatform admin, treat the toolbar fragment as the UI anchor and static files as the place for the tool's behavior. This keeps the layout light, separates responsibilities clearly, improves debugging, and works well for both simple shortcuts and complex admin tools.

Table Of Contents