Skip to main content
Version: 24.3

TeamRoom Plugin Integrations

This topic explains how to integrate TeamRoom in Agility.

Concept

The Digital.ai Agility TeamRoom™ feature allows users to use Agility without all of the noise. Most people do not use every feature every day, but they do tend to use a handful of the same features every day. TeamRooms tie simplified navigation with strong data filters to help people focus on what matters most.

However, as many features Agility has, every company uses other tools to get their work done. Using the REST API you can build integrations to help synchronize those together. One thing that was lacking though was a visual experience inside of the app.

TeamRoom Plugins are a way for developers to create visual elements and integrations that 'live' inside of a TeamRoom. Plugins communicate with the TeamRoom to produce things like Panels/Toggles or Radiators and can also receive messages like when a user changed the active iteration or selects an avatar to filter on.

Plugins are written in Javascript and can be hosted on your servers. But some plugins are generic enough and may be useful for other companies; in that case they can be shared and when installing the plugin they can be configured for your specific configuration.

We hope that you will find writing a plugin easy and intuitive and will build some great things to share with everyone in the Agility community!

Architecture

TeamRoom is built mostly on the client with Javascript and Backbone. Plugins are also written in Javascript but Backbone is not required. Plugins are actually hidden iframes that are injected into the TeamRoom. These hidden iframes are the entry point and communication hub of your plugin.

Plugins communicate with a TeamRoom through a message based protocol. Messages are serialized to JSON strings and sent through a secure boundary. TeamRooms receive the message, process it and send a callback message to the plugin. This asynchronous programming style is common in Javascript and allows us to create a strong boundary between a TeamRoom and its plugins.

Security

TeamRoom Plugins must be a hosted webpage. They are not run on the VersionOne server and are not even run inside of the TeamRoom window. Each iframe creates a new window that is completely isolated from its parent running a completely separate Javascript runtime. That means a plugin cannot 'reach out' into a TeamRoom and have a field day. In addition, since the plugin is hosted somewhere other than the V1 server it has to play by the very strict CORS rules set in place by browsers and cannot run arbitrary code under the user's identity.

So how then do messages go back and forth? The answer is in a browser API called postMessage that allows two windows to send string-only events to each other. That means that you cannot send arbitrary Javascript and further means that unsupported messages are ignored.

The advantage of this architecture and security model is that supported messages can and will be executed inside of the browser window as the user that is currently running. So queries and updates will have better security inside of the app than a generic 'robot' account that is common with integrations.

Quick Example

We ship a very basic plugin with Agility called Web Panel. This plugin allows the TeamRoom user to configure a new Toggle (name) and a corresponding Panel (url). That information is sent to the plugin upon start up and it in-turn sends a message to create a Panel with that information. Let's walk through that code:

Host

Every plugin must be hosted in a webpage. That page references a copy of the TeamRoomMessenger as well as whatever plugin code you write. It can be inline with the page, or a seperate file.

    <!DOCTYPE html>
<html><body>
<script type="text/javascript" src="../../dist/team-room-messenger.js"></script>
<script type="text/javascript" src="plugin.js"></script>
</body></html>

Initialization

Once your scripts are loaded the plugin must send an initialization command to the TeamRoom. This signals that you are ready to receieve and send messages. To get things started, we recommend using an immediately invoked function expression as good practice.

    (function () {
... below ...
})();

The first thing to do is create an instance of a TeamRoomMessenger. The constructor can take an optional options object to control the behavior of the messenger, one you may be interested in turning on right away is the debug option.

    var messenger = new TeamRoomMessenger({ debug:false });

When you are ready, send the init message. It is not necessary to supply a callback function when sending a message, but the init message in particular is useful to supply one as no messages will be processed until after you have received the callback.

    messenger.send('init', onInit);

Similar to node, an error object is supplied as the first parameter to any callback. It is highly recommended that you check this for a false value before continuing with your plugin messages.

    function onInit(err, args) {
if (err) throw err;

Sending a message

Assuming there is no error, the second argument is the args to the callback. This is an arbitrarily structure object depending on which message the callback is for. In this case we have registered the plugin to accept two configuration parameters Name and Url (more on this later).

        var panelArgs = { name : args.Name || 'Plugin' , url : args.url };

Coincidentally the add-panel message accepts two parameters as well, and we've copied the values from how the end user has configured this plugin. The values of these parameters do not have to come from configuration; you can hard-code them or pull from a different source all together.

        messenger.send('add-panel', panelArgs);
}

For the sake of simplicity we did not supply a callback argument as the third parameter. You probably should though so you can check the error argument to ensure you have successfully created a panel.

Receiving a message

Those are the basics on sending a message and receiving a callback. You can also register to receive messages originating from the TeamRoom with messenger.receive(message_name, callback). The callback looks just the same as it does when you send a message.

Registration

Currently anyone can register a plugin for use by any TeamRoom. Registering a plugin defines what it is and what configuration it needs to be fully functioning. It does not put it inside of any TeamRooms, it simply makes it available for TeamRoom configurators to install them into particular rooms.

Plugin registration happens through a minimalistic UI located in your app http://<host>/versionone/teamroomplugins.mvc/register. When registering you will need to provide:

Name - the name of the plugin as users see it

Description - a short message about what it does

URL - where the plugin webpage is hosted

Image - optional image to uniquely identify your plugin

Additionally you may ask the configurator to supply your plugin with the data that it needs. Plugins can have as many parameters as needed and each configuration parameter must be defined:

Id - the name of the variable to be sent to the plugin

Name - the name that the user will see when installing

Description - a short message about valid values or instructions

Validation Regular Expression - basic javascript validation to help prevent mistakes

Once a plugin has been defined, updates to its configuration are allowed by implicitly by registering a 'new' plugin but keeping the same hosted url. This will not force updates to existing installations of your plugin, so please be concious about changes.

Code

TeamRoomMessenger is the main interface you will use to communicate with a TeamRoom. It uses a ReceiveMessenger to listen for messages from the other window and SendMessenger to post messages to the other window. It also uses an additional SendMessenger to send callback messages that are bound to the original message.

Examples

web-panel

The most basic example. Start here.

drop-panel

Two panels with different droppable asset types.

API Messages

Interacting with the TeamRoomMessenger will require you to use callback functions. All callback functions have this structure.

    function callbackFn( 'err', { 'arg' : 'value' } ) { }

Sendable Messages

Send these messages from your plugin, always be sure to check the err in the callback to ensure success.

    messenger.send( 'name', { 'arg' : 'value' }, callbackFn ) {} );

Initialize

Indicates to the TeamRoom that your plugin page / script is ready to communicate. Send this message after document load, before you send any other messages. Messages sent before init will cause a callback with an err.

Name

init

Errors

Args

Callback Args

name : string

The name that the user has given this instance of the plugin.

< id > : string configurable

Any registered parameters will be added to the args object with the values that the user has configured this instance of the plugin with. The parameter Ids supplied during registration are used as the property names in this object.

Add Panel

Adds a panel and a toggle to the TeamRoom. The panel displays an iframe that can be pointed to any url. After the panel is added the callback will be invoked with a unique id identify it; you may add as many panels as you'd like. Each panel may have it's own TeamRoomMessenger to communicate with the room, but it is not a requirement. If you do want to communicate from the panel, be sure to send a panel-init message.

Name

add-panel

Errors

'not initialzied'

The plugin did not send an init message before sending this message.

Args

url : required string

The url that the iframe will display.

name : required string

The name of toggle button that controls visibility of the panel.

droppableAssetTypes : optional string array

An array of VersionOne asset types that are allowed to be dropped on the panel. An empty array or null/undefined specifies assets cannot be dropped on the panel.

Callback Args

panelId : string

A unique generated ID that you can reference later. This is especially useful if you add multiple panels from one plugin.

Panel Initialize

If you prefer to communicate directly from a panel that was added with add-panel rather than from your main plugin, you must send this message before sending others.

Name

panel-init

Errors

Args

Callback Args

Receivable Messages

Signing up to be notified when messages come from the TeamRoom has a similar structure to sending a message. The difference is that you supply a handler function instead of a callback function. A handler function looks similar to a callback function except that a third parameter is supplied: a callback function. Invoke the callback function when a response is required.

    messenger.receive( 'name', function handler( err, { 'arg' : 'value' }, callbackFn ) {} );

Panel Shown

When the user has toggled a panel to be visible that was added with add-panel.

Name

panel-shown

Args

panelId : required string

The unique generated ID that was supplied as a callback argument to the add-panel message.

Callback Args

Panel Hidden

When the user has toggled a panel to be invisible that was added with add-panel.

Name

panel-hidden

Args

panelId : required string

The unique generated ID that was supplied as a callback argument to the add-panel message.

Callback Args

Panel Drop

When the user dropped an asset onto a panel that was added with add-panel. Only asset types that were specified with droppableAssetTypes in the add-panel args will be able to be dropped.

Name

panel-drop

Args

panelId : required string

The unique generated ID that was supplied as a callback argument to the add-panel message.

asset : required object

oid : required string

assetType : required string

isClosed : required bool

Callback Args