ARRRRGGGGGHHHHHH!!!



Using TypeScript for Visual Studio Online Extensions


The new VSO extensibility model needs extensions to have a webserver today for hosting content like pages, javascript and css files and images. This webserver can be IIS, Node.js or something else. We are thinking to add an option in the future to host content inside VSO where the extension developers will not need to setup a website and they will provide a package which will contain all the content required by the UI integration. This will be especially helpful for integrations like menu actions where a javascript file is enough for action handlers (like this one).

However, no matter a website or a package is used for an extension, communication with the host is through javascript. There may be some extensions which do not require host communication like displaying a static page inside a hub but this scenario is out of the subject of this post.

The only thing needs to be done for communication is adding a reference for VSS.SDK.js to the page. This lets an extension:

  1. initialize VSS.SDK for communication
  2. register an action handler
  3. get notified when the page is ready (to talk to host)
  4. get context information about the host or extension
  5. use host services like dialog or history
  6. use a UI control provided by the host
  7. make a rest call to VSO for build, work, code, etc.

Starting from M82 (release notes), we generate a TypeScript declare file VSS.d.ts which will significantly improve the development experience if you use TypeScript (and we encourage you to do so). This declare file not only contains types for above listed communication steps but also for UI Controls and Rest Clients provided by VSO.

Once you add the below reference to the top of the TypeScript file, you should be good to go.

 /// <reference path='../typings/VSS' /> 

Please note that, you should also have jquery.d.ts, knockout.d.ts and q.d.ts right next to VSS.d.ts since some of the classes and interfaces rely on these libraries. You can find them either here or in DefinitelyTyped repo.

Then you'll get the intellisense for VSS module.

vss-intellisense

Declarations for UI Controls and Rest Clients

As mentioned before, VSS.d.ts contains types for both UI Controls and Rest Clients. However, they are different than SDK types. VSO uses  Asynchronous Module Definition (AMD) for loading javascript files and in order to use UI Controls and Rest Clients which requires the host to be instructed to setup module loader first using below code snippet. This will add necessary VSO styles and javascript files to the extension page and configure AMD loader.

 VSS.init({   setupModuleLoader: true   }); 

The rest is about adding necessary require statement and start using UI controls or Rest Clients. Here is a sample for our grid:

 import Controls = require("VSS/Controls"); import Grids = require("VSS/Controls/Grids");  var container = $(".my-container"); var gridOptions: Grids.IGridOptions = {   height: "300px",   width: "100%",   source: function () {     var result = [], i;     for (i = 0; i < 100; i++) {       result[result.length] = [i, "Column 2 text" + i, "Column 3 " + Math.random()];     }      return result;   } (),   columns: [     { text: "Column 1", index: 0, width: 50 },     { text: "Column 2", index: 1, width: 200, canSortBy: false },     { text: "Column 3", index: 2, width: 450 }] };  var grid = Controls.create<Grids.Grid, Grids.IGridOptions>(Grids.Grid, container, gridOptions); 

Here is a sample for a Rest Client which gets the list of projects from the account where extension is hosted:

 import Service = require("VSS/Service"); import Core_Contracts = require("TFS/Core/Contracts"); import Core_Client = require("TFS/Core/RestClient"); import WebApi_Constants = require("VSS/WebApi/Constants");  var client = Service.VssConnection   .getConnection()   .getHttpClient(Core_Client.CoreHttpClient, WebApi_Constants.ServiceInstanceTypes.TFS);    client.getProjects().then((projects: Core_Contracts.TeamProjectReference[]) => {   for (var p of projects) {     console.log(`Project name: ${p.name}, project id: ${p.id}, state: ${p.state}`);   }  }); 

How about Documentation?

We are working hard to add reference and samples for our client libraries. We do not have anything yet for SDK and UI Controls but added Reference for Rest Clients recently. Even Rest Client reference has a lot of missing doc but we are filling the gaps. We are also expecting to add doc and samples for SDK and UI Controls really soon.

Let us know if you have any feedback here.


Work Item Custom Control Development in TF Web Access 2012 – Deployment


In the previous post, we talked about the development changes of a Work Item Custom Control in the new version of Team Foundation Web Access. In this post, we'll dive into details of Work Item Custom Control deployment which is completely different than the previous version.

In TF Web Access 2010, you needed to place the assembly which contains the Work Item Custom Control implementation along with a manifest file in one of the search folders under Web Access installation folder. The manifest file (.wicc) was necessary for Web Access to resolve details about the custom control like assembly name the control lives in and the control type name.

New Web Access requires a zip package to be created which includes JavaScript files and a manifest file. The name of the manifest file must be manifest.xml and a typical content of it is as follows:

 <WebAccess version="11.0">  <plugin name="Voting Button Custom Control" vendor="Acme" moreinfo="https://www.acme.com" version="2.0.0" >   <modules>    <module namespace="Acme.VoteButton" kind="TFS.WorkItem.CustomControl"/>    </modules>  </plugin> </WebAccess> 

Plugin name, vendor, moreInfo and version attributes will appear in the extensions list of Web Access. It is possible to specify multiple modules inside a single extension package. Also please note that, the namespace attribute of the module should match the highlighted value below which exists in your JavaScript file and was explained in the previous post:

 TFS.module("Acme.VoteButton",   [     "TFS.WorkItemTracking.Controls",     "TFS.WorkItemTracking",     "TFS.Core"   ],   function () {     // custom control implementation   } ); 

The kind attribute of a module specifies the type of the module. Specify TFS.WorkItem.CustomControl as the kind value which ensures Web Access will load your module whenever the custom control is needed.

As mentioned in the previous post, you have to have two versions of the .js file, debug and min. During the development and testing phase, you can use the debug version of the .js file by cloning and renaming it to min.js but it is suggested that, you minify your .js file when the custom control is ready for the production.

Now you have the .js files and the manifest file ready, you can create your package. The simplest way of doing this is to place these three files in a temporary folder, select them all, right click and send to compressed folder.

image

You are free to specify any name for your package as it will not be used by Web Access.

After you created your package, you need to upload the package to Web Access and this is going to be done inside Web Access. Please note that, the scope of an extension package is for the application (or account for hosted TFS) meaning that it will be available to all project collections and projects. Extensions are not supported for TFS Hosted Preview because there is no way to customize the work item types for now.

In order to navigate to extensions management page you can either navigate directly to https://tfsinstance:8080/tfs/_admin/_Extensions page or navigate to https://tfsinstance:8080/tfs and click the administration icon on the upper right corner first.

image

And then click to extensions link to go to extensions management page.

image

Inside the extensions management page, click the plus icon to install your package.

image

From the dialog, click the browse button and specify the package you previously created. Then click OK button to upload the package.

image

By default, newly installed extensions are disabled. You need to activate the extension package by clicking "Enable" button on the right. Then click "OK" to pass the confirmation.

image

Also note that, as we mentioned earlier, you can see the extension details you specified in the manifest file in this list.

After having the extension package installed, you need to change the definition of the work item type which you want to add the custom control to. You can use witadmin command line tool to export and import work item type definitions.

On a computer which has Visual Studio installed, open the developer command prompt from All Programs\Visual Studio\Visual Studio Tools. Then export the desired work item type definition using the following command:

witadmin exportwitd /n:Bug /f:c:\temp\bug.xml /collection:https://tfsinstance:8080/tfs/collectionname /p:projectname

Open the exported work item type definition from the file path you specified in the command and add the field definition to Fields section if necessary (you can use the existing fields).

 <FIELD name="VoteButton" refname="ACME.VoteButton" type="Integer">  <HELPTEXT>Vote button</HELPTEXT> </FIELD> 

Then add the necessary entry to Form\Layout section for your custom control.

 <Control FieldName="ACME.VoteButton" Type="VoteButton" Label="Vote" LabelPosition="Left" /> 

Save the file and import the work item type definition using the following command to make your custom control appear in the work item form.

witadmin importwitd /f:c:\temp\bug.xml /collection:https://tfsinstance:8080/tfs/collectionname /p:projectname

You're done. After connecting to web access and opening a work item which has the custom control, you can see it in the form.

image

While implementing the custom control, package creation and upload steps will probably occur several times and we know that it is not fun. However, we are planning to make improvements on this area to have a seamless development environment. At the same time, you can refer to this blog post about a Fiddler trick to be able to change your JavaScript file without ever needing to install your package again and again.

Let us know if you have any questions or feedback.


Work Item Custom Control Development in TF Web Access 2012 - Development


One of the biggest investments we have made in the new version of Web Access is on the Work Item Tracking area. In TF Web Access 2010, we used to rely on WIT Client Object Model running on the server and it had been causing a number of issues (especially around shared cache) since it was initially designed to work for a single user through Visual Studio Team Explorer.

TF Web Access 2012 has a completely new architecture for Work Item Tracking where the rule processing logic is moved from the server to the browser. WIT Client Object Model is not used anymore and there is a thin Object Model written in JavaScript runs in the browser. The rules are executed in the browser and a direct communication is made to the server via XHR for only a few operations like save. Because there is no need for a roundtrip to the server to process the rules, performance significantly improved.

These changes impacted our Work Item Custom Control Development story significantly as you might have expected. We can categorize the changes in 2 areas: development and deployment. This post covers the development only and deployment is going to be a subject of another blog post.

In TF Web Access 2010, you needed to work on both server and client side when you were developing a custom control. Server side code was needed to interact with the work item object where you needed to inherit your custom control from IWorkItemWebControl. At the same time, JavaScript code needed in order to handle the UI interaction.

In the new version of Web Access, there is no server side development involved. Everything happens in the browser meaning that custom controls are written completely in JavaScript. Along with Web Access framework, jQuery and jQuery UI is also available for custom control developers.

You can start implementing your custom control with an empty JavaScript file. When specifying a name for your .js file, you'll need to have 2 separate versions of your JavaScript file for different flavors which is debug and min. If you chose a name like Acme.VoteButton for your JavaScript file, you'll need to have two files named Acme.VoteButton.debug.js and Acme.VoteButton.min.js. Web Access module loading system will then decide which file to load. We can ignore minified version for now, we'll talk about more on this in the deployment section.

The next thing you are going to do is define a module for your custom control(s). This is necessary to make your .js file integrate with the Web Access module loader so that it can take the advantage of on-demand loading and automatic flavor selection.

 TFS.module("Acme.VoteButton",   [     "TFS.WorkItemTracking.Controls",     "TFS.WorkItemTracking",     "TFS.Core"   ],   function () {     // custom control implementation   } ); 

Let's get into details of this expression.

TFS is a global variable belonging to Web Access framework which provides a utility method to define your module.

The first parameter of the module is a string which specifies a namespace for the module. Please note that this namespace should match the filename you specified for your .js file (the part before flavor).

The second parameter is an array of strings which specifies the dependencies of your module. The list in the above line is a typical list for the custom control development. Web Access module loader makes sure that the dependent modules are first loaded before your module gets executed.

The last parameter is a function which gets executed when the module is loaded and the actual module implementation lives in here. Optionally you can expose anything you want from your module by return an object.

The next step is adding shortcuts for common framework objects and functions to the top of main function. This step is optional but it makes the code cleaner and more readable.

 var WITOM = TFS.WorkItemTracking,   WITCONTROLS = TFS.WorkItemTracking.Controls,   delegate = TFS.Core.delegate; 

Then you can start implementing your custom control. The custom control must to be inherited from WorkItemControl which is provided by TFS.WorkItemTracking.Controls module. You'll also leverage the inheritance support of Web Access framework by using inherit utility function.

First, you define the constructor of your custom control. You never instantiate your custom control directly. It is going to be instantiated by Web Access. The only thing you need to do is register your custom control and we will get to that soon.

 // Constructor for VoteButton function VoteButton(container, options, workItemType) {   this.baseConstructor.call(this, container, options, workItemType); } 

And then your control implementation takes place by inheriting it from WorkItemControl. WorkItemControl provides a number of functions to be overridden by the custom control which is called during the life cycle of a custom control like bind, unbind, invalidate and flush.

 

 // VoteButton inherits from WorkItemControl VoteButton.inherit(WITCONTROLS.WorkItemControl, {   _control: null,    // Initialize the control UI without data (in "blank" state).   // Framework calls this method when the control needs to render its initial UI   // Notes:    // - The work item data is NOT available at this point   // - Keep in mind that work item form is reused for multiple work items    // by binding/unbinding the form to work item data   _init: function () {     this._base();     // Initialize your control by creating some UI elements and attaching to events   } }); 

Finally, the custom control must be registered using a control name. The control name is the name which is used in the work item type definition. When a work item form is rendered, Web Access looks for a registered control for the specified control name and if exists, it creates an instance of the registered control by providing a container, options and the work item type.

 // Register a work item custom control called "VoteButton" WITCONTROLS.registerWorkItemControl("VoteButton", VoteButton); 

Here is a list of most commonly used functions for a work item control:

_init()

This is called when a control is created. At this point, there is no work item bound to the control yet. When you think of Work Items View in Web Access, there is a possibility that a work item can be visible and invisible multiple times (especially when navigating through result of a query using keyboard). A control is not created every time it is displayed. Instead, it is created at first appearance and bound to the current work item. When another work item is displayed, control is unbound from the previous work item and bound to the new one (if the work items are of the same type).

bind(workItem)

This method is called when the control is being bound to a new work item.

unbind(workItem)

This method is called when the control is no longer bound to the specified work item

invalidate(flushing)

This method is called when the control needs to display with the current value (which is a field change caused by work item refresh, revert or save). If flushing is true then the value is being written to the work item field.

getControlValue()

This method is called to get the value of the control to write to the corresponding Work Item Tracking field

cleanup()

This method is called to allow the control to release reference to work item, detach from events, set members to null to free memory which is called after unbind.

clear()

This method is called to set control value to empty which is called after cleanup.

_container

This property is a jQuery object (DIV) which contains the control and sub elements are placed.

_getField()

This method gets the work item form field that corresponds to this control. _getField().getValue() and _getField().setValue(value) are used to read and modify the underlying work item fields. This method returns null if no field is associated with the control in the work item type definition.

And below is the complete content of the sample custom control.

 // Register this module as "ACME.VoteButton" and declare  // dependencies on TFS.WorkItemTracking.Controls, TFS.WorkItemTracking and TFS.Core modules TFS.module("Acme.VoteButton",   [     "TFS.WorkItemTracking.Controls",     "TFS.WorkItemTracking",     "TFS.Core"   ],   function () {    // module content    var WITOM = TFS.WorkItemTracking,     WITCONTROLS = TFS.WorkItemTracking.Controls,     delegate = TFS.Core.delegate;    // Constructor for VoteButton   function VoteButton(container, options, workItemType) {     this.baseConstructor.call(this, container, options, workItemType);   }    // VoteButton inherits from WorkItemControl   VoteButton.inherit(WITCONTROLS.WorkItemControl, {     _control: null,      // Initialize the control UI without data (in "blank" state).     // Framework calls this method when the control needs to render its initial UI     // Notes:      // - The work item data is NOT available at this point     // - Keep in mind that work item form is reused for multiple work items      // by binding/unbinding the form to work item data     _init: function () {       this._base();       this._control = $("<button type='submit'>Vote</button>").appendTo(this._container).bind("click", delegate(this, this._onClick));     },      // Update the control data     // Framework calls this method when the control needs to update itself, such as when:     // - work item form is bound to a specific work item     // - underlying field value has changed due to rules or another control logic     invalidate: function (flushing) {        // Get the vote count from the underlying field       var voteCount = this._getField().getValue() || 0;        // Display the number of votes if any       if (voteCount > 1) {         this._control.text(voteCount + " votes");       } else if (voteCount == 1) {         this._control.text(voteCount + " vote");       } else {         this._control.text("Vote");       }     },      // Clear the control data     // Framework calls this method when the control needs to reset its state to "blank", such as when:     // - work item form is unbound from a specific work item     clear: function () {       this._control.text("Vote");     },      // Handle the click event on the vote button     // Note: This is a private method for this control     _onClick: function () {       // Get the vote count from the underlying field       var voteCount = this._getField().getValue() || 0;        // Increment vote count       voteCount++;        // Store new vote count in the underlying field       this._getField().setValue(voteCount);      }    });     // Register this module as a work item custom control called "VoteButton"   WITCONTROLS.registerWorkItemControl("VoteButton", VoteButton);    return {     VoteButton: VoteButton   }; }); 

In the next post, we are going to talk about the deployment of a Work Item Custom Control.

Let us know if you have any questions or feedback.


Доступны материалы докладов с запуска Duet For Enterprise


 

На сайте конференции, посвященной запуску Duet for Enterprise, недавно выложили записи докладов:


Хозяйке на заметку: Процесс бюджетирования своими силами


С выходом продукта PerformancePoint 2007 заказчики получили доступный по стоимости инструмент, позволяющий решать задачи Business Intelligence – планирование, мониторинг ключевых показателей и анализ данных. Решения, существующие на рынке до этого, были доступны далеко не всем компаниям, прежде всего из за их стоимости. Однако позже было принято решение объединить PerformancePoint с Sharepoint, тем самым сделав эту технологию еще более доступной. При этом пришлось пожертвовать частью функционала – а именно модуль планирования.

 

image

Продолжая концепцию "Business Intelligence для всех" было сделано решение задачи бюджетирования, в котором использовались доступные всем технологии:

  • Sharepoint Server (предпочтительно 2010, но и с 2007 тоже можно)
  • Excel и Excel Services
  • SQL и SQL Integration Services
  • InfoPath и Forms Services
  • Visio и Visio Services
  • Workflow Foundation

Предлагаю партнерам и заказчикам оценить такой подход для решения важной бизнес задачи.


Расскажите о вашем решении, новый сайт SharePoint и новые курсы для разработчика


Долгое время я откладывал написание поста в блог – довольно много времени и сил отнимает смена позиции в Microsoft: отчет о выполненных делах и подготовка к будущим, новые инструменты, новые коллеги и т.д. Короче, теперь я работаю в департаменте Enterprise and Partner Group в позиции Solution Sales Professional, ну а по-русски это означает, что я отвечаю за продвижение решений на базе Office и на SharePoint платформе в крупных заказчиках. Вот добрался до "ЗаВолги", улегся в гамак, подключился с помощью 3G модема к Интернет и решил опубликовать все те новости, о которых хотелось написать за прошедшее время.

Честно говоря, с трудом приходится отбирать новости про SharePoint 2007, т.к. полным ходом идет подготовка к запуску SharePoint 2010 и очень трудно удержаться от рассказа про новые возможности :) Уже номинированы партнеры для участия в закрытом бета тестировании и, я надеюсь, многие разработчики уже совсем скоро смогут получить доступ к новой версии. Ну а пока, давайте пробежимся по некоторым новостям.

Готовые решения

Все больше появляется решений от партнеров на платформе SharePoint. На сайте Microsoft есть страница - Коробочные решения от партнеров. Попасть на нее можно отправив описание своего решения. Только это действительно должно быть коробочное решение, т.е. заказчик из описания должен понять:

  • какой он получит функционал
  • за какое время
  • за какие деньги
  • и как это будет потом поддерживаться.

Надо признаться, что далеко не все наработки партнеров могут быть опубликованы, плюс к тому процесс публикации может растянутся.

Чтобы упростить процедуру и дать возможность разместить не только коробочные решения, но и ваши веб-части, шаблоны, идеи -  я сделал страницу готовых решений на сайте Sharepoint-Community.ru.

Для того, чтобы разместить свое решение, достаточно отредактировать эту Wiki страницу, добавив свою ссылку. Я подписан на обновления этой страницы и утверждаю изменения, как только они поступают. Я и мои коллеги смогут ссылаться на эту страницу при общении с заказчиками, на мероприятиях и с других сайтов.

Все что требуется – зарегистрироваться на сайте с помощью вашего LiveID.

Новый официальный сайт SharePoint

Официальный сайт ShaePoint сделан на SharePoint - https://sharepoint.microsoft.com/.

Публикация контента на сайт разными авторами и редакторами происходит с помощью функционала Web Content Management портала SharePoint. На сайте вовсю используется Silverlight. Планируется, что с появлением бета версии SharePoint будет обновлен и сайт, используя новые возможности продукта.

Команда SharePoint опубликали статью о том, как был сделан этот сайт.

Новые курсы для разработчиков

Ресурс для начинающих разработчиков дополнен материалами об использовании SharePoint в Вебе - https://mssharepointdeveloper.com

Некоторые материалы еще находятся в состоянии подготовки, но уже сейчас можно скачать презентации, видео, лабораторные работы.

Заключение

Уже совсем скоро появится новая версия SharePoint и к продукту будет проявлен повышенный интерес. Имеет смысл как раз сейчас спозиционировать себя и свою компанию как специалистов в SharePoint и заявить о своих решениях.

Все больше появляется материалов об использовании SharePoint в Веб, а в новой версии использовать Sharepoint для Веб станет еще проще.


Бесплатный учебный курс для веб разработчиков на платформе SharePoint – готов!


Рад сообщить, что вышла вторая часть бесплатного учебного курса для веб-разработчиков на платформе SharePoint – Ramp Up: SharePoint for Developers

Picture1 Теперь в свободной форме можно изучить Sharepoint, будучи уверенным, что не осталось белых пятен в фундаментальных понятиях. А такая уверенность очень важна, когда используется технология с обширной предметной областью – ведь часто возникает риск "изобрести велосипед" при решении тех или иных задач.

Ну и, заодно, анонсирую скорые публикации по теме.

В рамках весенних TechDays уже подготовлены доклады, которые будут опубликованы в ближайшее время в треке SharePoint. Особое внимание будет уделено:

  • сценариям автоматизации процессов силами веб-разработчиков и веб-студий в условиях жесткой экономии средств заказчиком,
  • использованию платформы SharePoint в интернет и интранет сценариях,
  • теме управления Sharepoint с помощью PowerShell

Также находится в стадии финальной подготовки очень подробный учебный курс об использовании SharePoint для Интернет с лабораторными работами и документацией.

Как говорится Stay Tuned! :)