Implementing Server-Side UI Renderer
Server side renderers can be developed as separate python modules, and plugged into UI Agent backend using framework available in UI Agent Core. It is based on Stevedore Plugin framework.
Thanks to Stevedore and our comprehensively implemented base classes implementing your own renderer is very simple to start with. You just extend our classes, create the package, add it to Python environment during runtime and Stevedore will pick it up as a valid renderer to use.
To get a very good understanding what it takes to implement your own renderer it is worth going through the sources of our next_gen_ui_rhds_renderer as it's a good example of everything that needs doing. In the next sections of this guide we'll be referencing various pieces of this package to illustrate the approach.
A step by step guide to create a renderer plugin
Those instructions will assume you're implementing the plugin as part of our NextGenUI repository fork but it's also possible to implement it completely separate, you'll just have to align the steps with your project structure, build scripts etc.
- Clone NextGenUI repository or your fork of it.
- Create a subdirectory in
./libsdirectory that will contain source files for your renderer. By convention we tend to name our renderer packages with the pattern ofnext_gen_ui_******_rendererwith an example ofnext_gen_ui_rhds_renderer. This naming convention has no technical consequence, so it's up to you whether you follow it or not. - Add the
__init__.pyfile andREADME.mdfiles in your newly created plugin directory. - Create the main entrypoint script for your renderer. It'll extend classes provided in ./libs/next_gen_ui_agent/renderer/base_renderer.py. The code follows Factory and Strategy programming patterns to ease understanding and usage of the base implementation. You can also keep following ./libs/next_gen_ui_rhds_renderer/rhds_renderer.py for reference during implementing.
- Extend
StrategyFactoryabstract class and implement all the required methods. Theget_render_strategyone is the key handler of rendering. It's responsible for switching between different rendering strategies depending on the component type. On its output a class inheriting fromRenderStrategyBaseis expected. - Now for every component renderable by your system you have to provide a renderer strategy. You can see details about each type of the component and metadata it supports in our Compoments documentation.
Rendering strategies implementations can be shared between components or you can have some inheritance approach as you can see in RHDS Renderer. The most important part is to extend
RenderStrategyBaseand then provide instances of those classes from the factory. Please refer to code comments inRenderStrategyBaseto understand purpose of each of methods included in this class. If you just extend the class and provide no implementation, your renderer will already work and provide the default JSON responses. In our system we also provide an option to support Hand Build Components and for them to work you also have to provide custom strategy handler. - Create a
BUILDfile for our Pants build and monorepo management system. - The easiest will be to copy the one from ./libs/next_gen_ui_rhds_renderer/BUILD to start
- Update standard names, dependencies etc. values in it to be aligned with your project and its needs
- The crucial part to make the plugin discoverable by Stevedore is
entrypointssection:First two lines must not be changed as our Stevedore plugin manager is configured to look for plugins inentry_points={ "next_gen_ui.agent.renderer_factory": [ "rhds = next_gen_ui_rhds_renderer:RhdsStrategyFactory" ], },next_gen_ui.agent.renderer_factorynamespace. What you need to align with your code is the 3rd line. You need to replacerhdswith your short name which later will be used as a renderer key when invoking NextGenUI. Then on the right side comes reference to your package and class that extendsStrategyFactoryfrom ./libs/next_gen_ui_agent/renderer/base_renderer.py which you have written in the previous step. - Either write tests (see next section) or create your own script to run Next Gen UI Agent with the new renderer
Writing renderer tests
Basically renderer tests can be written as standard Python tests. You can find a lot examples in RHDS Renderer sources but also in the main agent's JSON renderer at ./libs/next_gen_ui_agent/renderer/json/*_test.py files.
Additionally, our base renderer provides also shareable tests which give you this possibility to just extend the classes they provide and gain at least basic level of testing that the output rendered contains certain tested fields. The root classes providing shareable tests can be found in ./libs/next_gen_ui_agent/renderer/*_shareable_tests.py files. To see how easy it is to use them you can see e.g. TestOneCardRHDSRendererWithShareableTests
class TestOneCardRHDSRendererWithShareableTests(BaseOneCardRendererTests):
"""Test class for RHDS renderer using shared test cases for one-card component."""
def get_strategy_factory(self) -> StrategyFactory:
return RhdsStrategyFactory()