How to: Create a custom toolbar menu in a VSO extension

Background

Visual Studio Online (VSO) will support the creation of extensions that will allow a developer to extend the functionality provided to VSO users. The ability to extend VSO requires that you are part of the Visual Studio Partner program (which is free). For more information on writing VSO extensions check out VSO’s Integrate site.

I’m going to assume that you have been able to create a VSO extension that contributes an action to VSO.  If not, you will want to look at Create your first extension with Visual Studio for the background information.  Once you understand the basics, you are ready to jump in to something slightly more complex.  Creating a drop-down menu in a VSO extension requires a little bit of extra JavaScript but nothing difficult.  I’ve created a zip file with all of the code used in this post, so you could also just grab that code and I’ll walk you through the interesting parts.

At the end of this article you should be able to create a drop-down menu from a VSO work item toolbar as shown in Figure 1 and understand the mechanics behind creating VSO Extensions with these capabilities.

SNAGHTML21a55b8

Step 1: Create a contribution point in the work item toolbar.

Start by opening the extension.json file.  This file holds the extension’s manifest as well as all of the contributions the extension provides to VSO.  The important piece is the contributions section in the following code:

{"namespace": "steve.workitemdemo","version": "0.0.1","name": "Work Item Manipulation Demo VSO Extension","description": "Demo","provider": {"name": "Steve St. Jean"   },   "baseUri": "https://localhost:44304",   "icon": "https://localhost:44304/images/steve-demo-icon.png",   "contributions": {      "vss.work.web#workItemToolbarActions": [         {         "id": "dupewi",         "text": "Duplicates",         "icon": "images/show-properties.png",         "group": "actions",         "uri": "main.html"         }      ]   }}

The contributions section is where you tell VSO where you want your menu to appear.  The vss.work.web#workItemToolbarActions value tells VSO that we want to create an action on the work item toolbar in the Work hub.  The work item toolbar is the toolbar in the Work Item form on the Queries hub as well as on the work item form when you open a work item as shown in Figures 2 & 3SNAGHTML21b60b0

SNAGHTML220b3d9

The important attributes in the contribution definition for our purposes are id, group, and uri.

contributions": {   "vss.work.web#workItemToolbarActions": [      {      "id": "dupewi",      "text": "Duplicates",      "icon": "images/show-properties.png",      "group": "actions",      "uri": "main.html"      }   ]}

The id value is going to be our anchor point.  We will need to write some JavaScript to extend the toolbar.  That JavaScript will be inside the function that VSO will call when it looks for the definition of the dupewi contribution.

The group value tells VSO that dupewi is going to do something.  In our case it is going to display a menu.

The uri value tells VSO which page to call when it needs information about the dupewi action.

That’s all we need to get this hooked up.

Step 2: Define the dupewi menu in main.html

When VSO loads the Queries hub or loads a work item it will see that we have extended its functionality.  Our manifest says that the code to retrieve for the extension can be found in main.html.  VSO will call out and load main.html and begin processing the <script> tags on the page.  The key to creating our menu is in the VSS.register(“dupewi”) function.  VSS.register takes the name of the contribution point and an object that implements the IContributedMenuSource interface.  IContributedMenuSource has two members, execute() and getMenuItems().  Most of the demos out there simply use the execute() method to return a callback that will be run when the user clicks on the item in the toolbar.  To create the drop-down menus, we need to also use the getMenuItems() function to return an array of menu object which can each have a child array of menu items.

Typically, the VSS.register() for an action only has an execute() member.  This is because the information needed to render the toolbar item is stored in the extension.json manifest file.  All VSO needs in that case is the execute() function as a callback to invoke when the user clicks on our contribution as shown in Figure 4.

SNAGHTML246d88e

In our case, we want to completely override the contribution information set in the extension.json file with our own menu.  We are now using the dupewi contribution as a hook to get our code to run so that we can define the menu and sub-menus in code.

Figure 5 shows the getMenuItems() member of dupewi which contains a function that constructs our array of menu items and returns that array to VSO for rendering.

SNAGHTML250bca9

Now let’s look at how we construct the top-level menu.  We start off creating a variable called menuItems that will hold the array of object literals that describe our menus.  We then create our top-level menu item.  This is the item we will see on the toolbar when the drop-down menu is collapsed.

Notice in Figure 6 that the top-level menu’s id value is dupewi just like we had in our extensions.json file.  This causes our definition to override the definition found in extensions.json.

Notice that we are missing a text value.  The text value is used to render text next to the icon in the toolbar.  Since we don’t have a text value our contribution will render as an icon only.

The icon value points to the location of the icon graphic that will be show in the toolbar when the contribution is rendered and the title value will be rendered as the tooltip for the icon.

The childItems[] array of object literals where we create the sub-menus.

SNAGHTML2546f03

The childItems[] array contains three child menu object literals as shown in Figure 7.  Each child menu has a unique id, has a text value to display as the menu name, has an action() member which returns a callback function that will be triggered when the menu item is clicked, and contains an icon value which is empty in this case.

Note

As of the date of this article there is a bug in VSO that requires the icon member to be defined even if it is not used. This is the reason you see the icon: “” text in the code in Figure 7.  If the icon member is not present then VSO will fail to render the entire contribution.  This bug has been fixed but the new code has not been rolled out to all of the VSO scale units as of 18-July-2015.

SNAGHTML25f1bad

Summary

That’s it.  Creating the child menus is as simple as defining a contribution point in the extension.json file and then using the VSS.register() function to generate a new set of menu items for VSO to display.  After you have deployed your extension to your web server and upload your extension.json to your VSO account you should be seeing your top-level menu appear in the work item toolbar.

Code

The code for this article can be downloaded from here: HSGBT_custom_toolbar_menu_vso_ext.zip