To keep the logic of Plugins isolated, every service, component, utility, and type related to a specific Plugin is
implemented under the /plugins folder. This allows us to easily add, change, and remove supported Plugins.
The Plugin Encapsulation logic is currently implemented through the pluginRegistryUtils utility file and other
components (e.g. <PluginFilterComponent />) and utilities (e.g. useSlotSingleFunction) located under the /shared
folder.
-
Plugin: Defines the governance, asset management, and/or membership of a DAO. A DAO can have one or more plugins installed depending on their governance needs. More information about the plugins' implementation at the smart-contract level can be found here.
-
Plugin Registry: A registry that collects information about the Plugins and how to display Plugin-specific data on the UI.
-
Slot: Identified by an ID (e.g.,
GOVERNANCE_DAO_MEMBER_LIST), it defines a section of the Application that changes depending on the DAO Plugin. -
Slot Component: A Plugin-specific React component used by the Application to render any kind of data in a specific Slot.
A Plugin is identified by an ID and registered at startup through the registerPlugin function of the
pluginRegistryUtils utility. The Plugin Registry then uses the Plugin information to check if a specific Plugin of a
DAO is supported by the Application.
Example of Plugin definition:
export const plugin: IPlugin = {
id: 'multisig',
name: 'Multisig',
};Example of Plugin registration:
import { plugin } from './constants/plugin';
export const initialiseMultisigPlugin = () => {
pluginRegistryUtils.registerPlugin(plugin);
};The Plugin Registry is a record containing information about the available Plugins and their Slot Components. It is
implemented as a JavaScript class in the
pluginRegistryUtils
file and populated on the client side at startup by the
<Providers />
component of the Application module. The <Providers /> component imports and triggers the
initialisePlugins function, which initializes all the
supported plugins by registering the Plugin information and their Slot Components.
A Slot is identified by an ID. Every Plugin can register its own Slots to customize how the Application displays or acts
depending on the Plugin of the DAO. Different types of Slots can be supported depending on the customization needs of
the Application. For instance, a SlotFunction type can be used by the Application to prefetch data on the server side,
or a SlotMetadata type can be used to only set some strings needed by the Application to render some Plugin
information.
The Slot ID is prefixed by the module name to easily identify the scope of the Slot.
Example of Slot definition:
export enum GovernanceSlotId {
GOVERNANCE_DAO_MEMBER_LIST = 'GOVERNANCE_DAO_MEMBER_LIST',
GOVERNANCE_MEMBERS_PAGE_DETAILS = 'GOVERNANCE_MEMBERS_PAGE_DETAILS',
}A Slot Component is a type of Slot that specifies a Component to be rendered in the Application. Slot Components are
implemented under the related Plugin folder and registered in the Plugin Registry through the registerSlotComponent
function.
Example of Slot Component registration:
export const initialiseMultisigPlugin = () => {
pluginRegistryUtils.registerSlotComponent({
slotId: GovernanceSlotId.GOVERNANCE_DAO_MEMBER_LIST,
pluginId: plugin.id,
component: MultisigMemberList,
});
};-
The
<PluginSingleComponent />React component is located under the/shared/componentsfolder and renders a Slot Component from a given Slot ID and Plugin ID. -
The
<PluginFilterComponent />React component supports rendering multiple Slot Components for the given Slot ID and Plugins. The component renders Slot Components through a Tab component to be able to switch between the Slot Component views.
To support a new Plugin in the Application, make sure to:
-
Create a new subfolder under the
/src/pluginsfolder (e.g.,/src/plugins/gaslessPlugin); -
Implement the Plugin definitions in a
/constants/plugin.tsfile by following theIPlugininterface. -
Implement all the required Slot Components for the new Plugin. All the available Slot Components are defined under a
/constants/moduleSlots.tsfile inside each module (e.g.,/modules/governance/constants/moduleSlots.ts). -
Create an
index.tsfile under the new Plugin folder exporting a function which initialises the Plugin by registering its Plugin definitions and Slot Components, e.g.:export const initialiseGaslessPlugin = () => { pluginRegistryUtils .registerPlugin(plugin) .registerSlotComponent({ slotId: GovernanceSlotId.GOVERNANCE_DAO_MEMBER_LIST, pluginId: plugin.id, component: GaslessMemberList, }) .registerSlotComponent({ slotId: GovernanceSlotId.GOVERNANCE_MEMBERS_PAGE_DETAILS, pluginId: plugin.id, component: GaslessMembersPageDetails, }); };
-
Update the
initialisePluginsfunction in the/plugins/index.tsfile to initialise the new Plugin.