Your first custom widget
#
What are widgets?- They are Components that can be added to a dashboard.
- They can be saved and reused.
- They can accept action plugins to make them more interactive.
ActiveUI comes with many stock widgets that require no coding to use.
However, any React Component can be turned into an ActiveUI widget.
This means that we can develop our own widgets!
#
Your first custom widgetWe will start with a "Hello World!" to get that first bit of code on the screen.
Let's create a couple of new files inside src
next to plugins.tsx
.
#
Widget FileThe first file contains our widget Component. Since we are building a map of the world, let's name it Map.tsx
.
import React, { FC } from "react";import { WidgetPluginProps } from "@activeviam/activeui-sdk";
export const Map: FC<WidgetPluginProps> = (props) => { return <div>Hello World!</div>;};
Map
is a Function Component that accepts WidgetPluginProps
(but does not use them yet) and simply returns a div
containing "Hello World!".
note
We will demystify WidgetPluginProps
later on in this section.
#
Plugin Widget FileLets create the second file in the same location and call it pluginWidgetMap.ts
.
TIP: Naming plugins
Take note of the naming here. When defining plugins its good practice to stick with the following formula:
- Start with
"plugin"
. - Reveal the type of
"plugin"
. In this case it is a"widget"
, but it also could have been a"cell"
or a"menuItem"
. - Provide the underlying component's name . In this case we are calling it
"map"
.
That brings us to a final name of pluginWidgetMap
.
import { WidgetPlugin } from "@activeviam/activeui-sdk";
import { Map } from "./Map";
const widgetKey = "map";
export const pluginWidgetMap: WidgetPlugin = { Component: Map, initialState: { widgetKey, }, key: widgetKey,};
Let's stop a minute and decipher this.
We defined pluginWidgetMap
which is a widget plugin. But what is widget plugin?
Simply put, a widget plugin is an object containing all the information needed to register a new widget in ActiveUI.
By editing this object, we can change how this widget will look and behave.
pluginWidgetMap
contains three properties so far:
- Component is the thing that actually gets displayed. In our case it is
Map
. - key identifies the widget, which will be useful when we want to display it in a dashboard.
- initialState is a bit more complex and we will explore it more in the next section.
#
Extend ActiveUILet's wire our new widget into ActiveUI!
- Open up
plugins.tsx
. - Add
pluginWidgetMap
into thewidgetPlugins
array.
note
The widgetPlugins array is eventually passed to the plugin registry. This is how ActiveUI knows what plugins it has.
+ import { pluginWidgetMap } from "./pluginWidgetMap";...
// Make sure to put it at the top of `widgetPlugins` so it becomes the first widget in the Widgets Ribbon. This will make it easier to find in the coming steps.const widgetPlugins: Array<WidgetPlugin> = [+ pluginWidgetMap, pluginWidgetPivotTable, ...]
It worked! Our new widget appeared:
We can drag and drop it into the dashboard to see our Component:
…but there are a few strange things going on:
- Without styling, "Hello world!" is stuck on the left edge.
- The question mark icon in the widgets ribbon does not relate to our widget at all.
- There are two weird labels:
aui.plugins.widget.map.key
when you hover the map icon in the widgets ribbon.aui.plugins.widget.map.defaultName
in the widget's title in the upper left corner of the widget.
Let's scratch these itches before we move on.
tip
To improve your experience, save the dashboard now. Your URL will now end with /dashboard/<id> where "id" is a short string. From here on out, each time you refresh the page, you will end up directly on your widget.
#
Add StyleSince Map
is a React Component, we could easily hardcode a horizontal padding onto it. However, our widget can be used in other contexts (like an atoti notebook) where that hardcoded style might not look good.
For this reason, widgets accept a style
prop passed in from their parents. This style
prop contains all the styling needed to make a widget look good inside its parent. Now we just have to wire that styling in.
const Map: FC<WidgetPluginProps> = (props) => { return (- <div>+ <div style={props.style}> Hello World! </div> );};
With this change, Map
allows its parent (in our case, the dashboard) to control its style. Now our map will look good in a dashboard as well as in a notebook (which would pass its own style
object down).
#
Add an iconBecause pluginWidgetMap
is a WidgetPlugin
, it has an Icon
property where we can attach an icon to represent our Component.
We will download a new file, IconWorld.tsx
. It contains a React Component that displays a globe icon. This makes it perfect for our map! Click here to download it.
Place IconWorld.tsx
next to Map.tsx
and wire it into our pluginWidgetMap
's Icon
property:
+ import { IconWorld } from "./IconWorld";
export const pluginWidgetMap: WidgetPlugin = { Component: Map,+ Icon: IconWorld, initialState: { widgetKey, }, key: widgetKey, };
#
Add translationsNow on to those two weird labels we spotted earlier.
Because ActiveUI is made to work with any language, it expects plugins to provide translations for all the locales it is going to support, starting with en-US
.
While you can have as many translation entries as you like, the following two are required for all widgets:
key
, used on the icon's tooltip.defaultName
, used as a placeholder for the widget's title.
You might be asking youself: how did they know to use key
and defaultName
?
These keys are actually the last words in the weird labels we spotted: aui.plugins.widget.map.key
and aui.plugins.widget.map.defaultName
. ActiveUI adds the other text based on what kind of plugin you're using (WidgetPlugin
in our case) and the plugin's key.
Let's head back into pluginWidgetMap.ts
to add a translations
property to the plugin:
import { IconWorld } from "./IconWorld";
export const pluginWidgetMap: WidgetPlugin = { Component: Map, Icon: IconWorld, initialState: { widgetKey, }, key: widgetKey,+ translations: {+ "en-US": {+ key: "Map",+ defaultName: "New map"+ }+ }};
note
You can (and should) add more translations every time you add another caption to your widget. This way, you will fully support your widget's different locales. More on this later in the tutorial. 😊
Congratulations, you just created your first ActiveUI widget!