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


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.


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": {      "": [         {         "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 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


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

contributions": {   "": [      {      "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.


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.


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.


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.


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.



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.


The code for this article can be downloaded from here:

Team Foundation Service is open to the public (and free!)

SNAGHTML80a046dThe Visual Studio Team has hit another major milestone in the evolution of Team Foundation Server.  Back at the BUILD conference last year they announce a hosted TFS offering called Team Foundation Service.  This hosted solution brings TFS based Work Item Tracking, Version Control and Automated Build through a browser and is connectable from Visual Studio just like an on-premises deployment of Team Foundation Server.  Use of the service was limited to those few that were able to get their hands on an Invitation Code.  This was done primarily to allow for a slow ramp-up in users of the service to help find and remedy scalability problems.

“Since we announced the Team Foundation Service Preview at the BUILD conference last year, we’ve limited the onboarding of new customers by requiring invitation codes to create accounts.  The main reason for this has been to control the growth of the service to make sure it didn’t run away from us and end up with a bad user experience.  In this time period, we’ve continued to work on our infrastructure, performance, scale, monitoring, management and, of course, some cool new features like cloud build. ”   – Brian Harry

Today, Brian Harry announced that there is no longer the need for an Invitation Code.  The Service is now open to the Public.  This means that they are confident in the service’s ability to handle the load as well as their ability to monitor activity and upgrade the service with little disruption to the global user community.

They are still offering the service without charge and while they get the final pieces in place to offer a complete commercial service.

“The service will remain in “preview” for a while longer while we work through additional features like data portability, commercial terms, etc but the terms of service support production use, the service is reliable and we expect to carry all of your data forward into production. ”  – Brian Harry

Brian has an excellent walk-through on how to get access to the service and begin playing with the service, the cloud-hosted build servers and the new Azure continuous deployment features.

Brian’s complete post can be found at