Skip to content

Instantly share code, notes, and snippets.

@tiagobento2
Created May 9, 2019 15:51
Show Gist options
  • Save tiagobento2/ede6cd33c97f0d4893d51a5983b35620 to your computer and use it in GitHub Desktop.
Save tiagobento2/ede6cd33c97f0d4893d51a5983b35620 to your computer and use it in GitHub Desktop.

AppFormer.js

This week, AppFormer.js initiative PRs were merged into KIE master branches. It means that now it's possible to write React componentes and use them inside Business Central! 🎉

In this post, I'll show how we achieved this and what needs to be done to create your own AppFormer.js components using React and integrate them in Business Central.

Contents

  1. The programming model
  2. Setting up your environment
  3. Creating a Maven module for your NPM package
  4. Creating your AppFormer.js component
  5. Integrating into Business Central
  6. Running and live-reloading your changes during development

 

The programming model

AppFomer.js was created with the goal of being a next generation of the AppFormer programming model. By implenting a well-defined contract, components can be reused by different platforms and abstract their underlying technologies.

If you're familiar with UberFire, you know that Perspectives, Screens, Editors (and others) are what make this programming model consistent. With AppFormer.js, it's no different. We chose Perspectives and Screens as the first two contracts to be defined, but it can be extended to cover more of it, like Editors, for instance.

In this first moment, we built these contracts having React and GWT components in mind so we could end up with an abstraction that covered both bases. We're also going to use TypeScript in order to keep our types explicit and have a good understanding of the programming model.

So what does an AppFormer.js component look like? It's pretty straightforward. Imagine you have a React component like this.

https://gist.github.com/af0f3c7547c756208b2cae1b6af258bc

Turning it into an AppFormer.Screen or AppFormer.Perspective is simple:

https://gist.github.com/2b947071f96bc70c694b84e5ea2dd033

https://gist.github.com/9f91a3b9e480ca7a6acfb5c7255e2232

A few things are worth noting in these examples:

  1. this.af_isReact = true is what indicates that a component is a React component.
  2. the super constructor call is what defined the unique id of the component.
  3. AppFormer.js has its own lifecycle. I encourage you to explore the AppFormer.Screen definition to see which methods are available.
  4. React components that translate into AppFormer.js components must be class components, so you can integrate it with AppFormer.js lifecycle.
  5. This prop called self is what exposes the React component to AppFormer.js. Although that is an antipattern, it's very useful here. Be aware that you should not abuse this construction and always try and keep the single directional data-flow consistent.
  6. AppFormer.register[Screen/Perspective] is what actually creates your components. Remember to call it!

 

Setting up your environment

If you already have the kiegroup repositories set up, you can skip this section.

First, make sure you have these:

  • Java 8
  • Maven 3.5.4
  • Node v11.6.0
  • Yarn v1.12.3

Now clone this repo https://github.com//tiagobento/kiegroup-all and follow the instructions on the README.md file. Instead of a normal mvn clean install, use this command:

mvn clean install -Denforcer.skip -Dgwt.compiler.skip -DskipTests -Dgwt.skipCompilation

It will speed up the compilation a bit.

You should see a BUILD SUCCESS message.

Great!

We're ready to create a new Mavenzied NPM Package integrated with Business Central's build!

 

Creating a Maven module for your NPM package

We'll be creating a very simple AppFormer.Screen inside Business Central's Library, just like the new Spaces Screen. But before we start coding, we need to configure our Mavenized NPM package inside Business Central's build. Because Business Central's Library is inside kie-wb-common, that's where we're going to add our new module.

The first thing we need is an NPM package where our TypeScript code will be, I'll provide an starter NPM package configuration with the tools we encourage you to use, but feel free to make your own configuration. We're gonna call our NPM package kie-wb-common-library-afjs-first-screen.

Two things are very important, though:

  1. You must use the same react and react-dom versions that Business Central provides: 16.6.0
  2. React and ReactDOM themselves must NOT be inside your final component bundle, so if you're using Webpack, make sure that both react and react-dom are marked as external.

One other very important thing is that appformer-js must be fetched using mvn, not npm. How does that work? We create a pom.xml file that will fetch the org.ubefire:appformer-js:[version] JAR for us and will extract it inside a directory on the root of our NPM package. Then we will alter our NPM package's package.json to point to appformer-js as a local NPM package instead of a NPM package coming from the NPM registry. Like this:

https://gist.github.com/1639e99f65dd3ffe233a333ac41b2d42

So you if feel more comfortable downloading a starer Mavenized NPM package, click here.

If you want to configure it by yourself, make sure to call your directory kie-wb-common-library-afjs-first-screen.

Now, move the kie-wb-common-library-afjs-first-screen directory to kiegroup-all/kie-wb-common/kie-wb-common-screens/kie-wb-common-library.

We just have to change kiegroup-all/kie-wb-common/kie-wb-common-screens/kie-wb-common-library/pom.xml to see our new module, so apply this:

https://gist.github.com/ae493bfd318bb17b289388d6e5e2038d

On kiegroup-all root, run:

mvn clean install -DskipTests -f kie-wb-common/kie-wb-common-screens/kie-wb-common-library/pom.xml.

You should see a BUILD SUCCESS message.

Great!

We already have our NPM package configured and integrated as a Maven module inside kiegroup/kie-wb-common build. Now it's time for us to create our AppFormer.js component inside it!

 

Creating your AppFormer.js component

On your favorite editor, open kie-wb-common-library-afjs-first-screen/src/index.tsx. For the sake of simplicity, we're going to create our AppFormer.Screen and our sub-components on the same file. You can download the file here.

The first thing we have to do is create a class extending AppFormer.Screen an make sure to register it. Like so:

https://gist.github.com/627c420f8adf0e63f4a53f2512ae185c

Now, we can get creative and create a React component to go along with our screen. If you're familiar with React tutorials, you know that we're creating a Counter component 🙂

https://gist.github.com/8ae180107d76a087e6e600a9ebd22677

More than just a Counter, this is a CounterCard, as it contains CSS that will match Business Central's look & feel. At last, we can use the CounterCard component we just created inside our AppFormer.Screen. So apply these changes to AfjsFirstScreen

https://gist.github.com/0cd8233b54e64d630adbe1d388ba67da

Like the CounterCard component we just created, these changes also contain CSS to match Business Central's look & feel.

On kiegroup-all root, run:

mvn clean install -DskipTests -f kie-wb-common/kie-wb-common-screens/kie-wb-common-library/kie-wb-common-library-afjs-first-screen/pom.xml.

You should see a BUILD SUCCESS message.

Great!

Your first AppFormer.js component is ready to be used in Business Central! Let's do this with some very simple configurations.

 

Integrating into Business Central

For the sake of this tutorial, we're not going to use the full sized Business Central version. Instead, we're going to work with Drools Workbench, which is an application that has some of the features Business Central and is optimized for development. Don't worry! The process of adding an AppFormer.js component on Business Central is exactly the same.

Note that because Business Central and Drools Workbench both already have AppFormer.js components integrated, there's already a line of code to "activate" the AppFormer.js capabilities. It's usually located on an @EntryPoint class for AppFormer.js to be available at the very beginning of the app. You can take a look at the @PostConstruct-annotated method on org/drools/workbench/client/DroolsWorkbenchEntryPoint.java if you want. The argument to AppFormerJsBridge#init should be the exact same name of the GWT module being compiled because we'll use that to assemble the URL to lazyly load the AppFormer.js components.

The repository where we're going to work now is drools-wb, and the module is drools-wb-webapp. Open it on your favorite editor or IDE and apply the changes below.

On kiegroup-all/drools-wb/drools-wb-webapp/pom.xml, add this execution configuration on the maven-dependency-plugin executions tag: https://gist.github.com/c88fafa0a098a7d2bc90e46e81f69a67

On the same file, add this execution configuration on the maven-resources-plugin executions tag.

https://gist.github.com/91714f3daf245dbe4fffbc3cb8a54356

These togheter will unpack kie-wb-common-library-afjs-first-screen JAR, which contains our component's bunlded JavaScript and copy this bundle to the application's output directory. It's conventioned that every AppFormer.js component bundle must be under /org/uberfire/jsbridge/public, or it won't work.

Last configuration we have to do before changing the application to have some way to access our new screen is to pur our component's information on AppFormer.js registry. All AppFormer.js components are lazily loaded, so we have to register it so AppFormer.js knows when and what to fetch.

On kiegroup-all/drools-wb/drools-wb-webapp/src/main/resources/org/uberfire/jsbridge/public/AppFormerComponentsRegistry.js, add this entry:

https://gist.github.com/a7b7989b5f290f060de1d66a40646465

We're almost there. To make our screen accessible, we're going to add an item to the Menu of the application. Go to org.drools.workbench.client.DroolsWorkbenchEntryPoint and add these lines on the setupMenu method.

https://gist.github.com/adf4093de19505160fb146b3079e06c9

Now let's bring the application up so we can (finally! 🎉) see our new screen.

On kiegroup-all root, run:

mvn clean gwt:run -f drools-wb/drools-wb-webapp

Wait for the "errai bus started." message on your console and go to "http://localhost:8888". Log in with admin/admin and wait for the compilation to finish. When the application starts, go to Menu > AppFormer.js First Screen. Voilà! There it is. Click around so you can see that our component actually works.

That's what you should see:

AppFormer.js First Screen on Drools Workbench

Great!

Your AppFormer.js component is up and running inside Business Central! Now let's see how to speed up the development workflow.

 

Running and live-reloading your changes during development

This only works on macOS and Linux at the moment.

If we want to change something on our recently created AppFormer.js component without bringing Business Central (or Drools Workbench in this case) down, everything we have to do it to change the bunlded JavaScript file inside the running application. To do that, we can simply execute a "copy" command. With a bit of bash scripting knowledge, we can achieve this:

Go to kiegroup-all/kie-wb-common/kie-wb-common-screens/kie-wb-common-library/kie-wb-common-library-afjs-first-screen and run:

npx watch 'yarn run live-reload-on ~/redhat/kiegroup-all/drools-wb/drools-wb-webapp' ./src

This will run the watch command inside /node_modules/.bin and execute the command yarn run live-reload-on ~/redhat/kiegroup-all/drools-wb/drools-wb-webapp everytime something on ./src changes. The argument yo yarn run live-reload-on is the location of your running application. In my case it was ~/redhat/kiegroup-all/drools-wb/drools-wb-webapp. Pretty handy!

If you're curious you can see how it's done on kie-wb-common-library-afjs-first-screen/package.json.

To see that it works, change something on kie-wb-common-library-afjs-first-screen/src/index.tsx, wait for the build to finish, go to your browser and refresh the page. After navigating to AppFormer.js First Screen, you should see your changes there.

Great!

Now you can easily change and see the changes you made inside Business Central!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment