Setup
Configuring custom actions is a two-step process:
Add custom action descriptor information to the custom action configuration file.
Create a corresponding custom action hoon source code file that's executed based when a poll is closed.
By default, Ballot comes pre-canned with a configuration file containing two basic custom-actions and two custom action source code files.
Configuration
Custom actions are made available thru Ballot using a json configuration file. This configuration file can be found in the following location of the ship's desk:
<desk>/lib/ballot/custom-actions/config.json
The config file follows a specific format. It's basically a generic key/value map (dictionary) of custom action keys to action detail. The information found in this file is used to render elements in the Ballot UI. Let's take a look:
Each top level element (e.g. custom-action-key) is a "key" - a unique value across all other keys found in the file.
Below is a description of each of the elements found in the configuration file:
custom-action-key - a value (unique to all other keys in the config file) which can be used to uniquely identify the custom action (e.g. 'invite-member')
label - a user-friendly label (name) of the custom action as it will appear in the Ballot UI (e.g. 'Invite Member' for the invite-member action)
description - describe the custom action. This information will also be displayed in the Ballot UI. use this description to help your users understand the purpose of the custom action.
form - a custom action may require inputs to carry out its task. Elements defined in this section are rendered in the proposal editor UI and used to capture inputs that are ultimately passed to the custom action at runtime.
For example, in the case of the default invite-member action, this action requires the ship name of the member to invite. The form section is used to define the requirements of the UI fields needed to capture the required input data.
field - the name of the field as it appears in the UI. in the case of invite-member, the field name is
member
. Thevalue
of thefield
element is the Hoon data type. In the case of invite-member, this iscord
to indicate a string cord
Here's the default ballot configuration file provided when the Ballot application is installed:
Hoon Spec
Custom action source code is stored in the following folder on the desk:
<desk>/lib/ballot/custom-actions
Ballot comes installed with two hoon source files located within this folder: invite-member.hoon
and kick-member.hoon
Take note of the names of these files. As part of the specification, custom action source files must be named after the custom action key located in the configuration file. Since there are two keys in the default config.json
file, there must two hoon files "backing" these settings.
In order to function propery, each custom action source file must contain two cores (parent -> child) where the parent contains an arm (on
) and the "child" core contains an arm (action
).
Both the parent core/arm and action core/arm take arguments which we'll look at in more detail later, but first let's review the invite-member.hoon
file located in the <desk>/lib/ballot/custom-actions
folder. There you will find the expected structure and format of a custom action handler. Note that in addition to the inline comments seen in the hoon code below, you can find additional information
The first thing you'll notice are references to sur
include files. At a bare minimum, your custom action will need to include plugin
and ballot
. The resource and invite-store are specific to this particular action (use-case). Therefore, custom actions you write will vary depending on use-case.
Required sur
include files
sur
include filesplugin - contains type/structure definitions required for the custom action to interoperate within the broader context of the Ballot app
ballot - contains the
root
store of the Ballot application. The root store is basically generic dictionary(map @t json)
.
lib
files
lib
filesAlthough the default custom action source does not include references to lib
files, your use-case may require the use of lib
files. Include them at the top of this file using the /+
rune. For example (my-lib-here
):
Parent core
The body of the on
parent core is a single core containing a single arm action
. This action arm returns an action-result instance (defined in plugin.hoon). Ballot is expecting all valid plugins to return data using the action-result structure.
action
accepts to arguments:
action-data
sample
action-data
is populated based on how the action is configured. Its values are determined by the form that is associated with the custom action, and selections that the user has made when creating the proposal. For example, in the case of the invite-member custom action, action-data will be provided as indicated above; where s+member is the cord
indicating the ship to invite.
payload (json) - proposal vote tally results
If the tally fails (e.g. not enough voter support), expect to receive data in the following format:
If the tally succeeds:
Notice in the success tally object above there's a tallies property which contains an array of tally detail objects. Each tally object found within the tallies array takes the following form:
Last updated