Popular Node.JS + React admin panel, AdminBro just got version 3.3 — the biggest release this year

Wojciech Krysiak
ITNEXT
Published in
11 min readNov 2, 2020

--

…so far :)

During the last month, at SoftwareBrothers we were working on the next release of admin-bro — an automated admin panel for Node.js apps. It meant to be a regular, minor release, but when we were working on it, new ideas started to come up and we ended up with a huge update. In this article, I will guide you through the new stuff which you can use right away after yarn add admin-bro@latest.

First, take a look at those big areas we’ve updated:

  • New configuration options
  • Handling nested schemas even if ORMs doesn’t handle them well (aka JSONB support)
  • Design System update with new components
  • New hooks for easier customization and data management
  • Better data manipulation with the flat module
  • Architectural changes improving the quality of the product (some of them can break your existing app)

Hope you are as excited as we are :) so let’s move to the details.

New configuration options

In this release we added new (requested by the users) options to actions and properties:

  1. “moving out” elements in the navigation: navigation

This option lets you easily move out one element in the navigation to the top level which previously had to be done by overriding the navigation component, which wasn’t super easy to do.

In the following screenshot users has been moved to the “root” level:

2. Nesting actions

We noticed that when you have lots of custom actions — they don’t fit in the UI easily and the only way to fix that was to disable rendering them automatically (to set hideActionHeader options to false) and then, render them on your own. Again — not an easy task to do.

In v3.3 we’ve introduced options for nesting actions — the same way you nest resources into parents. You can do this with new Action#parent option.

Nested actions look like this:

You can nest either bulk, record or resource actions as well.

3. Action variants

Another UI problem was that all the actions looked the same. Since we have a colour variant in the DesignSystem we can now allow you to pass it to your action, thus it can be emphasized.

This is how record actions section looks with button action set to “danger” variant:

4. New custom option in the Action

In PropertyOptions there was always a custom option which was passed (inside PropertyJSON) to your components so that you can configure them from the backend and make them more reusable.

In v.3.3 we also added a similar property to Action options. You can set it here and it will be available in your custom action.

5. New props option in PropertyOptions

AdminBro core renders well standard properties like input, password, text-areas etc. But there are countless options which can be added to modify the basic behaviour like placeholder, margins, size etc. That is why we’ve added new option props which is baked into the props we pass to the actual input component selected for a given property type.

Let me give you an example:

If you pass the following props to the property of type “string” (rendering <Input> component):

{
borderless: ‘true’,
variant: ‘xxl’,
placeholder: ‘fill me in’,
}

You will have the following input in your form:

6. Ability to hide the label

Apart from the new props option, you can now hide the label above the input — which could make sense in the example above with big borderless input.

You can do it here.

7. ResourceJSON.properties

The next thing is not about the option, but the response. We’ve added a map of properties to the ResourceJSON, so you can take any property from it with ease. There is no need to find Properties inside arrays like (edit | show | list | filter)Properties.

8. isArray and reference in PropertyOptions

Also, there are 2 new options which affect how properties handle nested data: isArray and reference. But these are results of one of the biggest changes we’ve made in the architecture. We’ve added support to define schemas for mixed properties.

Mixed properties and JSON(B)

Before v3.3 we relied totally on the adapters to handle relationships between resources (tables/collections) and nested schemas. This had lots of limitations, because:

  • Not all ORMs handle nested schemas in JSONB fields
  • Relationships (one to many) could be n handled only under one database
  • And, the worst of all, we had to maintain different implementations in all the adapters.

So in v3.3 we allow users to define data structures in AdminBro.

What does this mean?

Let me give you an example:

Let’s say you have a JSONB property defined in sequelize:

postImage: {
type: DataTypes.JSONB,
},

Now in your ResourceOptions you can define that this particular field is mixed and have size and path:

photoImage: {
type: 'mixed',
},
'photoImage.size': {
type: 'number',
},
'photoImage.path': {
type: 'string',
},

And admin will render it like this:

Now you can extend it with an… array of references (!!!) tags (where tags could relate to external API).

'photoImage.tags': {
reference: 'Tag',
isArray: true,
},

And this is how it will look right now with a nested array of tags inside this mixed property:

Isn’t that awesome?!

The same goes with typeorm adapter.

Design System

Since we extracted the Design System from the core in v3, every release we make some updates. It’s also the case with v3.3, but improvements are bigger than usual.

  1. New components

We added new “core” components to the family like:

2. UI improvements

We have improved the entire look and feel of the UI which was related to other new components: Navigation, ValueGroup and ButtonGroup.

Here I won’t put any screenshots — simply visit our Example app and see how that looks.

3. RichText component

We worked a lot on Quill integration in RichText component. Now it is backed to the DesignSystem bundle and easier to customize.

But… (another spoiler alert) we are exploring an option to integrate with slatejs — will see what the future brings.

3. themeGet

The last thing I want to mention when we talk about the design system update is a new utility function themeGet. It allows to easily fetch values from the design system based on the different scales (like space, fontWeights etc).

So instead of writing cumbersome:

margin: ${({ theme }) => theme.space.md} 0;

You can now write:

margin: ${themeGet(‘space’, ‘md’)} 0;

A little bit shorter, but with auto-completion from your IDE it’s a time saver.

New Hooks

Now let’s talk about hooks. AdminBro works well out of the box when you want to simply CRUD your data. But if you want to introduce a totally custom view it also gives you the tools to speed this up. And in this version v3.3, you can speed this up a lot with these amazing hooks.

useRecord

Use record hook has existed for some time in AdminBro, but it can now be customised and it returns more useful things.

What is the useRecord hook?

Basically, you use it when you want to create a new or update an existing record in the database right from the react component.

The v3.3 changes:

  • includeParams option: before v3.3 useRecord always sent all the parameters stored in the state, which made it hard to use simultaneously in 2 places because API calls overrode themselves. Now there is a `includeParams` option, which makes sure that only properties in this array are handled by the hook.
  • isSynced in the result. This allows you to perform automatic updates when the state in the hook is different than the state in the database.
  • setRecord function in the result which sets the state of an entire record.

For more information take a look at the documentation

useResource

This is a very “tiny”, but important hook. It allows you to fetch any ResourceJSON from the redux state. Documentation can be found here. You can use it in combination with useRecord

useResources, useSelectedResources and <RecordsTable> component

This trio allows you to fetch data from the backend and render a table of records for a given type. By using them, out of the box, you get features like:

  • Data fetching
  • Pagination
  • Columns rendering
  • Sorting
  • Selecting records
  • And even filtering when you put filter data in the query string

useAction

The last thing is the useAction hook. Basically, when you use custom (or builtin) actions in your components you should maintain all the logic defined in Action options like:

  • Make sure to print the alert when the action has a guard
  • Invoke the API call when the component is set to false
  • Etc.

With useAction — you have all this functionality computed and the only thing you have to do is to invoke handleClick returned by it.

Let me add that this hook is mostly used with <ActionButton />, an alternative way — the component which you can use inside JSX/TSX code

Flat module

All records data in AdminBro are stored in a flatten form. So if you are sending an array of strings from the component to the API we are sending something like this:

{
array.0: 'element1',
array.1: 'element2',
}

This is dictated by the fact that:

  • We use FromData between the React app and the API, which requires to have {[key: string]: string | File} form.
  • It is easier to update the database models when we have all the nested properties separated (in case of an entire object you always have to update the entire object)

Before v3.3 you maybe even didn’t notice that flatten thing. But in version 3.3 we improved support for mixed properties and we believe that this feature will be used more often.

That is why we also exported helper module: flat with:

  • functions modifying flatten records,
  • functions allowing you to work with them like with regular objects.

Apart from standard get and set methods you can also filterOut or select a given set of keys, as well as merge, flatten objects and regular objects together.

We use this module in every place when working with flatten data. In order to maintain consistency — you should too.

The documentation with a more detailed description can be found here.

Architectural changes — improvements

V3.3 is not a MAJOR release. But if you relied in your application on custom, complicated components — things might go wrong after the update to v3.3. These are the things you will have to check out:

  1. Flatten everywhere

Along with the flat module we fixed lots of places where things weren’t right (as the response after the update action which was both flat and “normal”). That is why when you relied on the wrong response you will have errors because now it is flattened.

2. The distinction between name, path and propertyPath in the PropertyJSON.

Before v3.3. each property definition had only a name which was an actual path in the flatten object when you received it in your custom component. That is why in order to change the record parameter you could use

onChange(property.name, 'your value').

It worked in a word when you don’t have complicated nested schemas, where the path to the property could be: my.super.0.complicated.1.field.12.name

That is why in v.3.3 we divided the name to 3 separate properties:

  • name itself became the actual property name — the last part of the path: name in the example above
  • path became the path of the actual value stored in the record — my.super.0.complicated.1.field.12.name from the example above
  • And finally: propertyPath which is a path to the property which defines it in PropertyOptions and allows you to get property from ResourceOption#properties map: In the example above propertyPath is my.super.complicatedfield.name

If you use components for rendering custom Arrays or nested fields — changing `property.name` to `property.path` will be required.

3. Design system components are taken from @admin-bro/design-system

When we extracted the Design System in v3.0 we instructed users to fetch its components from @admin-bro/design-system instead of admin-bro. But secretly, we left these 2 options open. In v3.3. admin-bro package does not export Design System components anymore (even secretly) so you have to change that If you haven’t yet.

4. useRecord does not reload itself when the `intialaRecord` argument changes.

Before v3.3 useRecord revalidated itself when the initialRecorpassed to the hook has been updated. As a reminder this is how you use useRecord:

const {
submit: submitTag,
record: tag, handleChange:
handleTag Change,
} = useRecord(initialRecord, “Tag”)

We changed that because it was not “compatible” with useState from React, which doesn’t update the state when its initial state argument changes.

If you relied on that — now you have to do this manually withuseEffect and the new paramsetRecord returned by useRecord.

5. bundled dependencies

In v3.3 the rollup bundler has been updated to the latest version. This fixed lots of issues with external dependencies imported in custom components, but it also might cause problems in your current setup if you used some hacks to fix the previous issues. Be aware of that.

Summary

Uff… these are the main things we have changed in v3.3. You can take a look at the release tag in GitHub to see the details, and other tinier, not-mentioned-here, updates.

As for the next thing — we are now thinking of v4 release. I will give you a heads up when things start to materialise but we plan at least 3 things:

  • Full DesignSystem update (we have a new, much slicker design almost done)
  • Bundler improvements — bundling will be much, much, much faster
  • and finally — Filtering Records, from the AdminBro you will be able to perform more complicated queries on the database.

A few actions for you before the above happens:

Cheers from the entire SoftwareBrothers team!

--

--

Co-founder and CTO at SoftwareBrothers, giving keynotes, providing open source solutions on GitHub and running a jscasts.tv youtube channel.