Microsoft

Opening Work items in Visual Studio “15” Preview

If you have used Visual Studio “15” Preview to connect to a Team Services instance, or you follow the Microsoft ALM blog you will have noticed that with the Visual Studio “15” Preview: Work items now open in the web from Visual Studio ’15’!

While the official post shows why that change was made and what advantages the web form brings, I wanted to quickly point out some small things that were done to make this behavior more usable.

You can follow along by downloading the Visual Studio “15” Preview and connecting to your Team Services or Team Foundation Server “15” RC1 instance.

Running Queries from Visual Studio

There is still the full work item query tree available in Visual Studio, including favorites:

team-explorer

You can also still create and run new or existing queries and look at the results:

query-1

If you look at the screenshot above, you can see that I have run the “My Bugs” query and that I have selected the second work item from the result, with id 62. When I open this work item now, it will launch in my browser and display the now familiar modern work item form:

Opened Work Item

And if you look closely, you can see that in the upper right hand corner of the work item form it displays “2 of 4” and some buttons:

query-3

When you open a work item from a query result in Visual Studio, we don’t want you lose the query context you were in. So, when opening the work item we pass some context information along, in this case this included the name of the query that you ran and the position of the work item inside of that query result. Then, in the web we can restore this context, show you the work item, and also give you the option to easily switch to the next/previous work item in the “My Bugs” query:

query-4

You can also just return to the full query result in the web:

query-5

Preserving the context this way works with all queries in Visual Studio, even new and unsaved ones.

New, unsaved query in Visual Studio

New, unsaved query in Visual Studio

Work item opened from query result in web

Work item opened from query result in web

Web query editor

Web query editor

Linking Work Items to Code Changes

With the Development section on the new work item form we have made it really easy to view code changes that contributed to work item, be it he implementation of a feature or a bugfix:

commit-dnd-result.png

To associate your code changes with your work items you can create a link after the fact from the work item form, or in Visual Studio when you commit or check in your code. For both Git and TFVC you can still run work item queries from the Changes or Pending Changes view and even drag and drop work items from the query result to the Related Work Items section. Adding a work item to a git commit:

Adding a related work item to a git commit

Adding a related work item to a git commit

Advertisements

VSTS Tags MRU extension – Part 1

I often find myself adding the same tags over and over to work items. Example: While we use features to group our user stories, it is often convenient to also add a tag per feature, since these can show up on the cards on the different boards, making it easy to see what belongs to which feature:

image

So let’s say I’m working on a feature called “Tag Extension”. Our feature is broken down into a few user stories and and we have applied a tag “Tag Extension” to all of them:

image

Then we add another story using the add panel on the backlog. It’s parented to the feature but it’s missing the tag applied to the other ones:

imageimage

While I could now open the user story and add the tag, what I’d like to have is something like this:

image

Open the context menu for a work item anywhere in the product, have a list of the tags I added last to any work item, and allowing me to easily add one of them with a single click.

Fortunately, we can build this with just a few lines of code using the VSTS extensions API. There is one little drawback – more on that later – but we can get quite close to what I just described. I will be using the seed project I mentioned earlier, you can just clone the repo or download it as a zip if you want to follow along: https://github.com/cschleiden/vsts-extension-ts-seed-simple.

You can also skip immediately ahead to the finished version:
https://github.com/cschleiden/vsts-extension-tags-mru

Capturing tags as they are added

The first task to generating the MRU list is to capture which tags are added to work items. In order to receive notifications about changes to the work item form, we need to add a contribution of type ms.vss-work-web.work-item-notifications to our extension. This allows us to listen to events like onFieldChanged (a field on the form has been changed) or onSaved (work item has been saved). So, we can just replace the existing contribution in the manifest with this:

{
  "id": "tags-mru-work-item-form-observer",
  "type": "ms.vss-work-web.work-item-notifications",
  "targets": [
  "ms.vss-work-web.work-item-form"
  ],
  "properties": {
  "uri": "index.html"
  }
}

and place the matching typescript code in app.ts (replacing the existing VSS.register call):

// Register work item change listener
VSS.register("tags-mru-work-item-form-observer", (context) => {
  return {
    onFieldChanged: (args) => {
      if (args.changedFields["System.Tags"]) {
        var changedTags: string = args.changedFields["System.Tags"];

        console.log(`Tags changed: ${changedTags}`);
      }
    },
    onLoaded: (args) => {
      console.log("Work item loaded");
    },
    onUnloaded: (args) => {
      console.log("Work item unloaded");
    },
    onSaved: (args) => {
      console.log("Work item saved");
    },
    onReset: (args) => {
      console.log("Work item reset");
    },
    onRefreshed: (args) => {
      console.log("Work item refreshed");
    }
  };
});

When we publish this extension to our account, create a new work item, add a couple tags, and then save the work item, we will see messages like these in the console:

image

As you can see, all tags are reported as a single field separated by semicolons. That means, that we need a way to identify when a tag is added. An easy way to accomplish this, is to get the list of tags when a work item is opened, and then when it’s saved to diff the original and current tags.

To get the tags when the work item is opened, we can utilize the WorkItemFormService. We need to import the framework module providing it:

import TFS_Wit_Services = require("TFS/WorkItemTracking/Services");

and then we can get an instance of the service when a work item is opened, and get the current value of the System.Tags field.

onLoaded: (args) => {
  // Get original tags from work item
  TFS_Wit_Services.WorkItemFormService.getService().then(wi => {
     (<IPromise<string>>wi.getFieldValue("System.Tags")).then(
    (changedTags: string) => {
      // TODO: Save
    });
  });
}

Since it’s possible to open multiple work items in VSTS at the same time, we cannot simply store original and updated tags in two variables, but need both current and updated tags keyed to a work item, identified by its id. A simple singleton solution could be the following:

/** Split tags into string array */
function splitTags(rawTags: string): string[] {
  return rawTags.split(";").map(t => t.trim());
}

/**
 * Tags are stored as a single field, separated by ";". 
 * We need to keep track of the tags when a work item was 
 * opened, and the ones when it's closed. The intersection 
 * are the tags added.
 */
class WorkItemTagsListener {
  private static instance: WorkItemTagsListener = null;

  public static getInstance(): WorkItemTagsListener {
    if (!WorkItemTagsListener.instance) {
      WorkItemTagsListener.instance = new WorkItemTagsListener();
    }

    return WorkItemTagsListener.instance;
  }

  /** Holds tags when work item was opened */
  private orgTags: { [workItemId: number]: string[] } = {};

  /** Tags added  */
  private newTags: { [workItemId: number]: string[] } = {};

  public setOriginalTags(workItemId: number, tags: string[]) {
    this.orgTags[workItemId] = tags;
  }

  public setNewTags(workItemId: number, tags: string[]) {
    this.newTags[workItemId] = tags;
  }    

  public clearForWorkItem(workItemId: number) {
    delete this.orgTags[workItemId];
    delete this.newTags[workItemId];
  }

  public commitTagsForWorkItem(workItemId: number): IPromise {
    // Generate intersection between old and new tags
    var diffTags = this.newTags[workItemId]
      .filter(t => this.orgTags[workItemId].indexOf(t) < 0);
    // TODO: Store
    return Q(null);
  }
}

hooking it up to the observer:

 // Register work item change listener VSS.register("tags-mru-work-item-form-observer", (context) => {
  return {
    onFieldChanged: (args) => {
      // (2)
      if (args.changedFields["System.Tags"]) {
        var changedTags: string = args.changedFields["System.Tags"];
        WorkItemTagsListener.getInstance()
            .setNewTags(args.id, splitTags(changedTags));
      }
    },
    onLoaded: (args) => {
      // (1)
      // Get original tags from work item
      TFS_Wit_Services.WorkItemFormService.getService().then(wi => {
        (<IPromise>wi.getFieldValue("System.Tags")).then(
        changedTagsRaw => {
          WorkItemTagsListener.getInstance()
             .setOriginalTags(args.id, splitTags(changedTagsRaw));
        });
      });
    },
    onUnloaded: (args) => {
      // (4)
      WorkItemTagsListener.getInstance().clearForWorkItem(args.id);
    },
    onSaved: (args) => {
      // (3)
      WorkItemTagsListener.getInstance().commitTagsForWorkItem(args.id);
    },
    onReset: (args) => {
      // (5)
      WorkItemTagsListener.getInstance().setNewTags(args.id, []);
    },
    onRefreshed: (args) => {
      // (5)
      WorkItemTagsListener.getInstance().setNewTags(args.id, []);
    }
  };
});
  1. Retrieve the tags of a work item when it’s opened, storing them in the WorkItemTagsListener instance
  2. Whenever the System.Tags field is changed, store the tags as the new tags in the TagsListener instance
  3. When the work item is actually saved, commit the new tags to the MRU list (not yet implemented)
  4. Reset the work item’s data when it’s unloaded
  5. Only reset the new tags when edits to a work item are discarded

This enables us to detect added tags to any work items. The next part will cover actually storing the tags per user, showing them in a context menu, and applying to work items.

Extending VSTS – Setup

Last year Visual Studio Team Services (formerly known as Visual Studio Online) released support for extensions. There are some great samples on GitHub and a growing number of finished extensions in the marketplace. One of my published extensions is Estimate, a planning poker implementation for VSTS.

Extending VSTS is really easy, there is documentation and some great examples at the official GitHub repository.

Since I work on the Agile planning tools and work item tracking, I would like to show with a few simple examples how you can add functionality to your backlogs, boards, and queries. To make it really easy I’ve published  a small seed project that contributes a single menu item to the work item context menu and which will be the base for some extensions with a bit more functionality. If you’re already familiar with VSTS extensions feel free to skip immediately to part 2.

image

The seed project is available at GitHub; here is a step by step description how to build, publish, and install it:

  1. First you need a VSTS account, it’s free, just register with your Microsoft account.
  2. Create a publisher: With your Microsoft account, sign in at the marketplace and pick an ID and a display name:
    image
  3. Generate a personal access token: Login to VSTS, go to My Security:

    security

    then to the Personal access tokens section:

    image

    generate a token for All accessible accounts:

    image
    copy and save the generate token for later:

    image
  4. Clone (or download as zip and extract) the seed project from:
    https://github.com/cschleiden/vsts-extension-ts-seed-simple
  5. Install nodejs
  6. cd into the folder where you placed the project in step 4
  7. Install required dependencies with
    npm install
  8. Open the extension manifest, vss-extension.json
  9. Change <your-publisher> to the publisher ID you created in step 2:

    image
  10. As part of step 5, the TFS Cross Platform Command Line Interface was installed. This will be used to package and publish the extension. Login to your account by executing
    tfx login --service-url https://marketplace.visualstudio.com

    when prompted for the token, use the one generated in step 3. This will save the login information for subsequent operations:
    image(Update: the uri has changed, please use https://marketplace.visualstudio.com)

  11. Finally, execute
    grunt publish-dev
    to build, package, and publish the extension using the development configuration. If everything works the output should be similar to this:

    image
  12. Share with your account: The extension has now been published as a private extension, no one else can see it yet. To test it, we need to share it with our account. There are two ways, one is using the tfx command line, the other is using again the Marketplace. When you login again you should now see the extension and a Share button:

    image

    Just share it with your account

    image
  13. Install: After sharing the extension, it should show up in the Manage extensions page of your VSTS account:

    image
    to install, select it, confirm, and allow the requested OAuth scopes:

    imageimage

    image
  14. Test: If you now navigate to a query result (create a query and some work items if you haven’t) and open the context menu for any work item, you should see the menu action contributed by the extension:

    image
    click will execute the registered action and show the id of the selected work item:

    image

Windows Phone 7.5 Mango und O2 Visual Voice Mail

Seit gestern wird die aktuelle Windows Phone 7 version “Mango” ausgeliefert (rockt uebrigens) und bringt (theoretisch) Support fuer Visual Voice Mail mit. O2 Deutschland Kunden (so wie ich) haben in dieser Hinsicht aber leider Pech, denn ein O2 Mitarbeiter schreibt im O2 Forum:

ja gibt es: Nach derzeitigem Stand wird es Visual Voicemail aus Kostengründen nicht für andere Plattformen als iOS geben. Sobald sich das ändert, werden wir dies rechtzeitig bekanntgeben.

(Quelle: http://forum.o2online.de/t5/Software-Firmware/Visual-Voice-Mail-f%C3%BCr-Windows-Phone-7-Mango/td-p/133754)

Schade.

Export Multiple Charts from Excel (Office) To PDF For LaTeX Inclusion At Once

I still receive a lot of hits for my earlier post about how to export Excel charts to PDF in order to include them in a LaTeX document. Various keywords also indicate that a lot of people want to kind of automate that process and export many charts at once. Luckily that is also possible now. I have not checked for the PC version yet (if you do it would be great if you could tell me in the comments or view some other channel but here is how-to for Microsoft Excel 2011 for the Mac:

1. Create your charts (that step should be obvious)

2. Select all your charts (hold shift and click):

3. Select “Save as Picture” from the context menu

4. Check the Box “Save each graphic as a separate file” and select format PDF:
 5. Enter a name. Note: The name entered here will result in Excel: a) creating a directory with the name b) saving each selected diagram with name “<entered-name>-<number>.pdf”. So for example “Charts”:
with the two earlier selected charts will result in:
6. All selected charts will be saved and automatically cropped, ready to be included in your document.

7. This works similarly in Microsoft Word and Microsoft Powerpoint.

 

Have fun.