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

Twitter and Bitly Plugin for Windows Live Writer 2012

Twitter-IconI’ve been playing around with the new WordPress blog, mostly getting it setup with my favorite blog editor Windows Live Writer.  I’ve used this tool in the past with great success. 

One of the nice things about WLW is that is has a nice plugin model.  One of the plugins that I used to use constantly is the Twitter plugin.  That plugin would post a tweet containing the blog title and a link right after you published the blog post to your site.  Unfortunately, I can’t seem to find that plugin anywhere on the Internet so I decided to cobble together my own. 

This is version 0.6.0, meaning that it is Beta software and hasn’t been tested extensively.  It works on my machine but I don’t guarantee that it will work on yours.  My development philosophy is “Make it work”, “Make it work right”, “Make it work well”.  This is definitely in the “Make it work” phase.  I need to add more error handling on the various web calls.pufferfishIconWriter

If you want to take a copy and use it/test it out for me I’d be grateful.  I’ve created a static page on my blog for the plugin so feel free to go there, download the plugin, and leave any feedback in the comments for that post (or here).

Here’s the page address: http://howstevegotburnedtoday.com/wlwtwitterplugin/