Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020
本文介绍如何使用扩展自定义工作项窗体。 可以在 Azure DevOps 中向工作项表单添加操作、观察者、组或页面。
小窍门
如果要启动新的 Azure DevOps 扩展,请先尝试这些维护的示例集合 -- 它们适用于当前产品版本并涵盖新式方案(例如,在拉取请求页上添加选项卡)。
- Azure DevOps 扩展示例 (GitHub)-一个演示常见扩展模式的紧凑初学者示例: https://github.com/microsoft/azure-devops-extension-sample
- Azure DevOps 扩展样例(旧版集合和贡献指南),安装以检查用户界面目标或查看源:https://marketplace.visualstudio.com/items/ms-samples.samples-contributions-guide 和 https://github.com/Microsoft/vso-extension-samples/tree/master/contributions-guide
- Microsoft Learn 示例(浏览 Azure DevOps 示例)- 跨 Microsoft 文档的精选、最新的示例:/samples/browse/?terms=azure%20devops%20extension
如果某个示例在组织中不起作用,请将其安装到个人或测试组织中,并将扩展清单的目标 ID 和 API 版本与当前文档进行比较。有关参考和 API,请参阅:
有关完整的源代码,请参阅 GitHub 上的 Azure DevOps 扩展示例中的 UI 示例。
添加组
              
               
              
              
            
若要向主页添加组,请向扩展清单添加贡献。 此贡献的类型应为 ms.vss-work-web.work-item-form-group,并且应针对 ms.vss-work-web.work-item-form 贡献。
"contributions": [
   {  
       "id": "sample-work-item-form-group",
       "type": "ms.vss-work-web.work-item-form-group",
       "description": "Custom work item form group",
       "targets": [
           "ms.vss-work-web.work-item-form"
       ],
       "properties": {
           "name": "My Group",
           "uri": "workItemGroup.html",
           "height": 600
       }
   }
]
属性
| 财产 | 说明 | 
|---|---|
| name | 组中显示的文本。 | 
| uri | 指向托管工作项窗体及其脚本上显示的 html 的页面的 URI。 | 
| height | (可选)定义组的高度。 省略时,其值为 100%。 | 
JavaScript 示例
此示例显示如何注册一个对象,当工作项窗体上发生可能影响你贡献的组的事件时,该对象会被调用。
import { IWorkItemFormService, WorkItemTrackingServiceIds } from "azure-devops-extension-api/WorkItemTracking";
import * as SDK from "azure-devops-extension-sdk";
// Get the WorkItemFormService.  This service allows you to get/set fields/links on the 'active' work item (the work item
// that currently is displayed in the UI).
async function getWorkItemFormService()
{
    const workItemFormService = await SDK.getService<IWorkItemFormService>(WorkItemTrackingServiceIds.WorkItemFormService);
    return workItemFormService;
}
// Register a listener for the work item group contribution after initializing the SDK.
SDK.register(SDK.getContributionId(), function () {
    return {
        // Called when the active work item is modified
        onFieldChanged: function(args) {
            $(".events").append($("<div/>").text("onFieldChanged - " + JSON.stringify(args)));
        },
        
        // Called when a new work item is being loaded in the UI
        onLoaded: function (args) {
            getWorkItemFormService().then(function(service) {            
                // Get the current values for a few of the common fields
                service.getFieldValues(["System.Id", "System.Title", "System.State", "System.CreatedDate"]).then(
                    function (value) {
                        $(".events").append($("<div/>").text("onLoaded - " + JSON.stringify(value)));
                    });
            });
        },
        
        // Called when the active work item is being unloaded in the UI
        onUnloaded: function (args) {
            $(".events").empty();
            $(".events").append($("<div/>").text("onUnloaded - " + JSON.stringify(args)));
        },
        
        // Called after the work item has been saved
        onSaved: function (args) {
            $(".events").append($("<div/>").text("onSaved - " + JSON.stringify(args)));
        },
        
        // Called when the work item is reset to its unmodified state (undo)
        onReset: function (args) {
            $(".events").append($("<div/>").text("onReset - " + JSON.stringify(args)));
        },
        
        // Called when the work item has been refreshed from the server
        onRefreshed: function (args) {
            $(".events").append($("<div/>").text("onRefreshed - " + JSON.stringify(args)));
        }
    }
});
事件
| 事件 | 事件说明 | 参数 | 自变量说明 | 
|---|---|---|---|
| onFieldChanged | 字段更改后触发。 如果字段更改运行规则更新了其他字段,则所有这些更改都是单个事件的一部分。 | ID | 工作项的编号 | 
| changedFields | 包含所有已更改字段的引用名称的数组。 | ID | 工作项的编号 | 
| onLoaded | 在数据加载到工作项窗体中、用户打开工作项或用户导航到会审视图中的另一个工作项时触发。 | ID | 工作项的编号 | 
| onReset | 在用户撤消对工作项的更改后触发。 | ID | 工作项的编号 | 
| onRefreshed | 用户手动刷新工作项后触发。 | ID | 工作项的编号 | 
| onSaved | 保存工作项后触发。 对于对话中的工作项,应把 ms.vss-work-web.work-item-notifications类型设为目标,以确保事件触发,因为一旦对话框关闭,此贡献类型就会被卸载。 有关详细信息,请参阅侦听事件。 | ID | 工作项的编号 | 
| onUnloaded | 在用户关闭对话框之前触发,或者在用户移动到会审视图中的另一个工作项之前触发。 | ID | 工作项的编号 | 
添加页面
工作项表单上会显示一个新的选项卡。 新页面显示在“ 详细信息 ”选项卡旁边。
              
               
              
              
            
若要向工作项窗体添加页面,请向扩展清单添加贡献。 此贡献的类型应为 ms.vss-work-web.work-item-form-page,并且应针对 ms.vss-work-web.work-item-form 贡献。
"contributions": [
    {  
        "id": "sample-work-item-form-page",
        "type": "ms.vss-work-web.work-item-form-page",
        "description": "Custom work item form page",
        "targets": [
            "ms.vss-work-web.work-item-form"
        ],
        "properties": {
            "name": "My Page",
            "uri": "workItemPage.html"
        } 
    }
]
属性
| 财产 | 说明 | 
|---|---|
| 名字 | 显示在选项卡页上的文本。 | 
| uri | 指向托管工作项窗体及其脚本上显示的 html 的页面的 URI。 | 
JavaScript 示例
请参阅窗体组部分中的 JavaScript 示例。 已注册对象的名称应与贡献的名称匹配 id 。
事件
| 事件 | 事件说明 | 参数 | 自变量说明 | 
|---|---|---|---|
| onFieldChanged | 字段更改后触发。 如果字段更改运行规则更新了其他字段,则所有这些更改都是单个事件的一部分。 | ID | 工作项的编号 | 
| changedFields | 包含所有已更改字段的引用名称的数组。 | ID | 工作项的编号 | 
| onLoaded | 在数据加载到工作项窗体中、用户打开工作项或用户导航到会审视图中的另一个工作项时触发。 | ID | 工作项的编号 | 
| onReset | 在用户撤消对工作项的更改后触发。 | ID | 工作项的编号 | 
| onRefreshed | 用户手动刷新工作项后触发。 | ID | 工作项的编号 | 
| onSaved | 保存工作项后触发。 对于对话中的工作项,应把 ms.vss-work-web.work-item-notifications类型设为目标,以确保事件触发,因为一旦对话框关闭,此贡献类型就会被卸载。 有关详细信息,请参阅侦听事件。 | ID | 工作项的编号 | 
| onUnloaded | 在用户关闭对话框之前触发,或者在用户移动到会审视图中的另一个工作项之前触发。 | ID | 工作项的编号 | 
在工作项窗体中配置贡献
在 Azure DevOps Services 中,默认情况下,组扩展显示在窗体的第二列末尾,页面贡献显示在所有工作项窗体页之后作为选项卡。默认情况下,控件贡献不会显示在窗体中,因此用户必须手动将其添加到窗体中。 在 Azure DevOps Server 中,若要在工作项窗体中显示/隐藏或移动控件、组和页面贡献,请参阅 “配置工作项”窗体扩展。
添加菜单操作
              
               
              
              
            
若要将项添加到工作项工具栏,请将此贡献添加到扩展清单。 选择工作项表单中的垂直省略号以查看下拉菜单。
"contributions": [
   {  
      "id": "sample-work-item-menu",  
      "type": "ms.vss-web.action",  
      "description": "Sample toolbar item which updates the title of a work item",  
      "targets": [  
          "ms.vss-work-web.work-item-context-menu"  
      ],  
      "properties": {  
          "text": "Try me!",  
          "title": "Updates the title of the work item from the extension",  
          "toolbarText": "Try me!",  
          "icon": "images/show-properties.png",  
          "uri": "menu-workItemToolbarButton.html"  
      }  
   }
]
属性
| 财产 | 说明 | 
|---|---|
| text | 显示在工具栏项上的文本。 | 
| title | 显示在菜单项上的工具提示文本。 | 
| toolbarText | 鼠标悬停于项目上时显示的文本。 | 
| uri | 用于注册工具栏操作处理程序的页面的 URI。 | 
| icon | 显示在菜单项上的图标的 URL。 使用 baseUri解析相对 URL。 | 
| group | 菜单项的显示位置由它与其他项的关系决定。 具有相同组名称的工具栏项将被分组,并通过分隔符与其他项分开。 | 
| registeredObjectId | (可选)已注册菜单操作处理程序的名称。 默认为贡献 ID。 | 
侦听事件
若要向侦听工作项事件的工作项添加观察者,请将此贡献添加到扩展清单中。 观察者在工作项窗体上没有可视化。 这是侦听工作项窗体 onSaved 事件的最佳方式,因为观察者位于窗体外部,当窗体关闭时不会被销毁,而窗体在保存后可能会立即关闭。
"contributions": [
   {  
       "id": "sample-work-item-form-observer",
       "type": "ms.vss-work-web.work-item-notifications",
       "description": "Gets events about the current work item form for the 'Try Me!' toolbar button",
       "targets": [
           "ms.vss-work-web.work-item-form"
       ],
       "properties": {
           "uri": "myformobserver.html"
       }
   }
]
属性
| 财产 | 说明 | 
|---|---|
| uri | 用于托管监听事件脚本的页面的 URI。 | 
事件
| 事件 | 事件说明 | 参数 | 自变量说明 | 
|---|---|---|---|
| onFieldChanged | 字段更改后触发。 如果字段更改运行规则更新了其他字段,则所有这些更改都是单个事件的一部分。 | ID | 工作项的编号 | 
| changedFields | 包含所有已更改字段的引用名称的数组。 | ID | 工作项的编号 | 
| onLoaded | 在数据加载到工作项窗体中、用户打开工作项或用户导航到会审视图中的另一个工作项时触发。 | ID | 工作项的编号 | 
| onReset | 在用户撤消对工作项的更改后触发。 | ID | 工作项的编号 | 
| onRefreshed | 用户手动刷新工作项后触发。 | ID | 工作项的编号 | 
| onSaved | 保存工作项后触发。 对于对话中的工作项,应把 ms.vss-work-web.work-item-notifications类型设为目标,以确保事件触发,因为一旦对话框关闭,此贡献类型就会被卸载。 有关详细信息,请参阅侦听事件。 | ID | 工作项的编号 | 
| onUnloaded | 在用户关闭对话框之前触发,或者在用户移动到会审视图中的另一个工作项之前触发。 | ID | 工作项的编号 | 
HTML/JavaScript 示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Work item extension page sample</title>
</head>
<body>
    <script src="sdk/scripts/SDK.js"></script>
    <script>
        SDK.init({
            usePlatformScripts: true
        });
        
        SDK.ready(function () {
             // Register a listener for the work item page contribution.
            SDK.register(SDK.getContributionId(), function () {
                return {
                    // Called when the active work item is modified
                    onFieldChanged: function(args) {
                        
                    },
                    
                    // Called when a new work item is being loaded in the UI
                    onLoaded: function (args) {
            
                    },
                    
                    // Called when the active work item is being unloaded in the UI
                    onUnloaded: function (args) {
            
                    },
                    
                    // Called after the work item has been saved
                    onSaved: function (args) {
            
                    },
                    
                    // Called when the work item is reset to its unmodified state (undo)
                    onReset: function (args) {
            
                    },
                    
                    // Called when the work item has been refreshed from the server
                    onRefreshed: function (args) {
            
                    }
                }
            });    
        });
     </script>
</body>
</html>    
New Boards Hub 的更改
注意
默认情况下启用了“全新面板中心”功能。 我们强烈建议您使用新的看板中心测试您的内部扩展,以确保兼容性。
使用最新的 SDK
确保扩展使用的是最新版本的 azure-devops-extension-sdk
使用新 SDK 时,还应使用适用于 REST API 的 azure-devops-extension-api 包。 我们每次冲刺更新方法和接口,以确保其中包含所有最新功能。
何时使用操作或操作提供程序
在菜单处理程序上使用 ms.vss-web.action-provider 动态加载菜单项时,请使用 getMenuItems。 避免在菜单项已静态化并在清单中定义时使用 ms.vss-web.action-provider。 应该改用 ms.vss-web.action。
软件包require("VSS/Events/Document")不再受支持
              全新面板中心不再支持 require("VSS/Events/Document") 导入。