Coder Social home page Coder Social logo

azure-devops-extension-sdk's Introduction

Azure DevOps Web Extension SDK

Release Notes

New major version, v4.*.* provides multiple module support to the SDK.

Details

  • ES Module Support: SDK now supports ES (ECMAScript) modules in addition to the existing AMD (Asynchronous Module Definition) modules. You can now import SDK using the ES module syntax, which provides performance improvements and reduces the application size.

  • Backward Compatibility for AMD Modules: Existing support for AMD modules remains intact. If your project is using AMD modules, you can continue to use them as before without any changes.

How to Use

If you're using AMD modules, you can continue to import SDK using the require function:

require(['azure-devops-extension-sdk'], function(SDK) {
  // Use the module here
});

For ES modules, you can import our modules using the import statement:

import * as SDK from 'azure-devops-extension-sdk';
// Use the module here

Get started with a new extension

See the Develop a web extension for Azure DevOps documentation for instructions on getting started with a new extension. You can also refer to the azure-devops-extension-sample repository as a working reference.

Overview

Client SDK for developing Azure DevOps extensions.

The client SDK enables web extensions to communicate to the host frame. It can be used to:

  • Notify the host that the extension is loaded or has errors
  • Get basic contextual information about the current page (current user, host and extension information)
  • Get theme information
  • Obtain an authorization token to use in REST calls back to Azure DevOps
  • Get remote services offered by the host frame

A full API reference of can be found here.

Get started with a new extension

See the Develop a web extension for Azure DevOps documentation for instructions on getting started with a new extension. You can also refer to the azure-devops-extension-sample repository as a working reference.

Import the SDK within your extension project

  1. Add azure-devops-extension-sdk to the list of dependencies in your package.json
  2. Add import * as SDK from "azure-devops-extension-sdk" to your TypeScript code

Initialize the SDK

When you have rendered your extension content, call SDK.init(). Your extension content will not be displayed until you have notified the host frame that you are ready. There are two options for doing this:

  1. Call SDK.init() with no loaded option
  2. Call SDK.init({ loaded: false }) to start initializing the SDK. Then call SDK.notifyLoadSucceeded() once you have finished your initial rendering. This allows you to make other SDK calls while your content is still loading (and hidden behind a spinner).

Example:

import * as SDK from "azure-devops-extension-sdk";

SDK.init();

API

A full API reference of can be found here.

Code of Conduct

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

azure-devops-extension-sdk's People

Contributors

50wliu avatar lohitakshgupta avatar microsoft-github-policy-service[bot] avatar misinformeddna avatar nkirchem avatar vadim-kovalyov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

azure-devops-extension-sdk's Issues

Target Date for Widget support?

Is there a target date for when widgets will be supported by this newer SDK? I am hesitant to develop on the old SDK and then have to port over to this one, but if the support for widgets isn't coming anytime soon then I'll just bite the bullet.

Extend project settings with azure devops sdk

Hello everyone,
I have a question for you.

I have old vss extension of project settings and it worked well, but I try to rewrite it to react and azure devops extension sdk and when I put my hub into project setting then i see page in menu but after click nothing is loaded, no progress indicator, nothing. If I put my hub into another place at devops (for example work items) then I see my page, so I think, everythings is OK with it. Is there any required settings, previlieges for show page with this sdk like project settings?

Have anyone same experience or can someone try it to place hub into project settings (ms.vss-web.project-admin-hub-group)? I want to know if it is my fault, or not.

Thanks
JM

Where are the types?

When I used vss-web-extension-sdk I had stuff like this at the top of tsx files:
/// <reference types="vss-web-extension-sdk" />

which somehow allowed typescript to find types like this:
import TFS_Wit_Contracts = require("TFS/WorkItemTracking/Contracts");

But if I try to use azure-devops instead of vss-web, therre is no longer a @types folder in my node_modules, and there is no @types/azure-devops-extension-sdk to download from npm.

So how do we load those TFS modules (and presumably also the VSS ones)?

Unable to clone - C:\>git clone https://github.com/leansoftX/ads-add-child-workitem.git Cloning into 'ads-add-child-workitem'... info: please complete authentication in your browser... remote: Repository `leansoftX/ads-add-child-workitem' is disabled. remote: Please ask the owner to check their account. fatal: unable to access 'https://github.com/leansoftX/ads-add-child-workitem.git/': The requested URL returned error: 403

I tried to clone your code in order to run npm audit on it, but I'm unable:

C:>git clone https://github.com/leansoftX/ads-add-child-workitem.git
Cloning into 'ads-add-child-workitem'...
info: please complete authentication in your browser...
remote: Repository `leansoftX/ads-add-child-workitem' is disabled.
remote: Please ask the owner to check their account.
fatal: unable to access 'https://github.com/leansoftX/ads-add-child-workitem.git/': The requested URL returned error: 403

Cannot create documents via the Extension Data APIs (404)

Hi folks. I'm trying to create a document using the Extensions Data API but I keep getting a 404 with the following response:

{"Message":"No HTTP resource was found that matches the request URI 'https://extmgmt.dev.azure.com/_apis/ExtensionManagement/InstalledExtensions/merge-a-bot/Data/Scopes/Default/Current/Collections/MergePolicies-Automerge/Documents'."}

Here is how my request looks like

POST: https://extmgmt.dev.azure.com/epignosisx/_apis/ExtensionManagement/InstalledExtensions/merge-a-bot/Data/Scopes/Default/Current/Collections/MergePolicies-Automerge/Documents

accept: application/json;api-version=3.2-preview.1;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
authorization: Bearer <omitted>
content-length: 95
content-type: application/json
origin: https://dev.azure.com
referer: https://dev.azure.com/epignosisx/Automerge/_apps/hub/alex-h.merge-a-bot.merge-policies-hub
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.37
x-tfs-fedauthredirect: Suppress
x-tfs-session: 94314739-d0c3-4584-a122-ddd3af09b314
x-vss-reauthenticationaction: Suppress


{"strategy":"SpecificSourceAndTargetPolicy","repo":"Automerge","source":"asdf","target":"asdf"}

Here is the outcome in the Network Tab:
image

This is how my code looks like:

export async function createPolicy(strategy: string, repo: string, source: string, target: string): Promise<void> {
    var context = SDK.getExtensionContext();
    var token = await SDK.getAccessToken();
    var dataService = await SDK.getService<IExtensionDataService>(CommonServiceIds.ExtensionDataService);
    var mng = await dataService.getExtensionDataManager(context.extensionId, token);
    var doc = await mng.createDocument("MergePolicies-" + repo, { strategy: strategy, repo: repo, source: source, target: target });
    console.log(doc);
}

and I'm making sure to initialize the SDK on page startup:

SDK.init().then(() => {
    ReactDOM.render(<App />, document.getElementById("root"));
})

Finally, I've been following this guide based on the old VSS and adapting it to the new SDK/API packages:

https://docs.microsoft.com/en-us/azure/devops/extend/develop/data-storage?view=azure-devops#create-a-document

Really appreciate your help here, I've run out of troubleshooting ideas.

Best way to handle secrets in Azure DevOps extensions.

I have an extension in which there is a need to use a higher privileged PAT token (than the currently logged in user) to work with the user entitlements rest api. This is because at this time there is no rest client available for user entitlements, as confirmed here.

What would be the best way to handle the PAT as a secret within extension code? I was planning to use Azure KeyVault as explained here but the value of the secret would still be accessible if I try to debug the extension from the browser (developer tools). This allows the end users to open up developer tools in the browser and then extract the PAT token.

What would be the best way to handle this scenario?

Getting 404 error from SetValue of IExtensionDataManager

Hi, I am not very familiar with Typescript and React yet, but I tried to write an extension hub to be used in Azure DevOps. I wanted to use extension data service to store some data, like users' selection in dropdown.

I read this: https://docs.microsoft.com/en-us/azure/devops/extend/develop/data-storage?view=azure-devops
, and tried to work with azure-devops-extension-sdk instead of vss-web-extension-sdk.

I tried to call setValue() as below, although it is not the full code:

public componentDidMount() {
        SDK.init();
        this.initializeComponent(); 
    }

private async initializeComponent() {
        await SDK.ready();
        const extContext = await SDK.getExtensionContext();
        const accessToken = await SDK.getAccessToken();
        const extService = await SDK.getService<IExtensionDataService>(CommonServiceIds.ExtensionDataService);
        const extDataManager = await extService.getExtensionDataManager(extContext.extensionId, accessToken);

        var result = await extDataManager.setValue("testKey","test123", {scopeType: "User"});
}

However, I get this error message:

PUT https://extmgmt.dev.azure.com/{my organisation}/_apis/ExtensionManagement/InstalledExtensions/{my extension}/Data/Scopes/User/Me/Collections/%24settings/Documents 404

My extension was working fine until I added the line of setValue().
I am not sure what causes the error. Hopefully I can get some help with it, thank you!

Custom picklist values in Pipeline Task

Hi,

I have created an extension that adds an Azure Pipelines Task. The inputs for the task contain a picklist and it's being populated by using sourceDefinitions. This has always worked fine but roughly around August 2022 it has stopped working.

The definition of the task looks like this:

    "inputs": [
        {
            "name": "workItemType",
            "type": "picklist",
            "label": "WorkItem Type",
            "defaultValue": "",
            "required": true,
            "helpMarkDown": "The type of workitems to update, e.g. User Story, Task or Bug. You can use a comma-separated string to supply multiple values."
        }
    ],
    "sourceDefinitions": [
        {
            "target": "workItemType",
            "endpoint": "/$(system.teamProject)/_apis/wit/workItemTypes?api-version=1.0",
            "selector": "jsonpath:$.value[*].name",
            "authKey": "tfs:teamfoundation"
        }        
    ]

If I try to populate the dropdown in the UI, it will execute a request to https://bluebasher-sandbox.visualstudio.com/_apis/distributedtask/endpoint
With the following payload:

{
    "url": "/TestWiki/_apis/wit/workItemTypes?api-version=1.0",
    "selector": "jsonpath:$.value[*].name",
    "connectionId": "tfs:00025394-6065-48CA-87D9-7F5672854EF7",
    "scope": "f9bd23c4-e6b5-4e71-96c7-d4daa63f7943",
    "taskId": "7164116a-ed17-48be-9c53-b440b2b1dd2e",
    "keySelector": ""
}

And it returns this error:

{
    "$id": "1",
    "innerException": null,
    "message": "No service connection found with identifier tfs:00025394-6065-48CA-87D9-7F5672854EF7.",
    "typeName": "Microsoft.TeamFoundation.DistributedTask.WebApi.EndpointNotFoundException, Microsoft.TeamFoundation.DistributedTask.WebApi",
    "typeKey": "EndpointNotFoundException",
    "errorCode": 0,
    "eventide": 3000
}

So it seems to me that somewhere the authkey tfs:teamfoundation is being replaced by an actual (internal?) Service Connection, which does not exists anymore?

How to size Custom Work Item Form Control (Dropdown) correctly?

Hi,

I've implemented a custom work item form control which just consists of a simple drop-down. The drop down items are bound through code and all works as expected except for the size of the drop-down list. I can specify the size if the control in the extension manifest through the height property. The dropdown list with the available values is sized based on the height property. If the height value is large, the drop-down list is show shown also larger but this has the downside that a lot of empty space is reserved on the work item form for this control. If the value is low (for example 70, which should be sufficient for a simple drop-down) the drop-list is really small (just showing one item).
I can see other built in drop-down list on a work item form which are using minimal space and the drop-down list is expanded and shown as a nice list. I need to know how to achieve this behavior for my custom control as well. Do I need to place specific CSS classes on my HTML elements? I experimented with different styles but none of them seem have an effect. This is my current rendering code:
<div className="flex-item" style={{ margin: "8px", width: "99%"}}>

I tried "flex", "flex-box".
Any hints?
Thanks.
Georg

Getting an error when i create react based Azure Devops Table with check box

Table columns used
export const checkboxColumns = [
new ColumnSelect(),
{
id: "name", name: "Name", readonly: true, renderCell: renderSimpleCell, width: new ObservableValue(-30),
},
{
id: "age", name: "Age", readonly: true, renderCell: renderSimpleCell, width: new ObservableValue(-30),
},
{
id: "gender", name: "Gender", readonly: true, renderCell: renderSimpleCell, width: new ObservableValue(-40),
},
];
Error Message Prompted
TS2322: Type '(ColumnSelect | { id: string; name: string; readonly: boolean; renderCell: (rowIndex: number, columnIndex: number, tableColumn: ITableColumn, tableItem: T, ariaRowIndex?: number | undefined) => Element; width: ObservableValue<...>; })[]' is not assignable to type 'ITableColumn[]'.
Type 'ColumnSelect | { id: string; name: string; readonly: boolean; renderCell: (rowIndex: number, columnIndex: number, tableColumn: ITableColumn, tableItem: T, ariaRowIndex?: number | undefined) => Element; width: ObservableValue<...>; }' is not assignable to type 'ITableColumn'.
Type 'ColumnSelect' is not assignable to type 'ITableColumn'.
Types of property 'behaviors' are incompatible.
Type 'IBehavior<ITableColumnBehaviorProps<{}>, {}>[]' is not assignable to type 'IBehavior<ITableColumnBehaviorProps, {}>[]'.
Type 'IBehavior<ITableColumnBehaviorProps<{}>, {}>' is not assignable to type 'IBehavior<ITableColumnBehaviorProps, {}>'.
Types of property 'initialize' are incompatible.
Type '((props: Readonly<ITableColumnBehaviorProps<{}>>, component: {}, eventDispatch: IEventDispatch) => void) | undefined' is not assignable to type '((props: Readonly<ITableColumnBehaviorProps>, component: {}, eventDispatch: IEventDispatch) => void) | undefined'.
Type '(props: Readonly<ITableColumnBehaviorProps<{}>>, component: {}, eventDispatch: IEventDispatch) => void' is not assignable to type '(props: Readonly<ITableColumnBehaviorProps>, component: {}, eventDispatch: IEventDispatch) => void'.
Types of parameters 'props' and 'props' are incompatible.
Type 'Readonly<ITableColumnBehaviorProps>' is not assignable to type 'Readonly<ITableColumnBehaviorProps<{}>>'.
Types of property 'tableProps' are incompatible.
Type 'Partial<ITableProps>' is not assignable to type 'Partial<ITableProps<{}>>'.

Code for Table Creation
import * as React from "react";
import { checkboxColumns, tableItems } from "./TableData";
import { ListSelection } from "azure-devops-ui/List";
import { Card } from "azure-devops-ui/Card";
import { Table } from "azure-devops-ui/Table";

export default class TableCheckboxExample extends React.Component {
private selection = new ListSelection({ selectOnFocus: true, multiSelect: true });

public render(): JSX.Element {
    return (
        <Card className="flex-grow bolt-table-card" contentProps={{ contentPadding: false }}>
            <Table
                ariaLabel="Table with checkboxes"
                className="table-example"
                columns={checkboxColumns}
                containerClassName="h-scroll-auto"
                itemProvider={tableItems}
                selection={this.selection}
                role="table"
            />
        </Card>
    );
}

}

Any way to get current team selected in backlog tabs

In the old VSS code we could use VSS.getWebContext() to get some information about current project and selected team, but there doesn't seem to be a way in the new SDK. I need to get team information in an extension I'm building which is adding a new tab to the backlog.

Unable to determine the board type in SDK.register instance context

In our project, we are adding one context menu item and respective actions against it. I just learned that, when we show this context menu(right click), the context which gets passed is actually different and there is no way to determine from where it has been invoked.
For example,
if we are in "Sprint Board" the context which I get has the workitem id as "id"
if we are in "Detailed View" (dialog view of any clicked item from Sprint board), we get workitem Id as "workItemId"
If we are in "Backlog View", we get workitem Id as array "workItemIds:[]"

Is there any we can determine the board/view, from where it is being called?

In *some* cases - 'nameid' claim does not contain user id in getAppToken() call

Hi,

We're using the method getAppToken() (https://docs.microsoft.com/en-us/javascript/api/azure-devops-extension-sdk/#getapptoken--) for authenticating to our backend, as described in this document:
https://docs.microsoft.com/en-us/azure/devops/extend/develop/auth?view=azure-devops#authenticating-requests-to-your-service. When validating the generated token in our backend, we get a claim nameid that contains a Guid. In most cases, this is the user Id of the logged in user. However, in approximately 1 out of 10 cases, we see that the nameid claim from the token does not correspond to the user Id of the user. Instead, it is some other Guid (we don't know what).

We haven't been able to find a pattern in cases where it does / does not work correctly :( can you provide guidance how to pinpoint the issue ?

Here's a link to the referenced method:

export async function getAppToken(): Promise<string> {

GlobalMessagesService onClick does not work for IDialog service

using azure-devops-extension-sdk 2.0.11, this is the code:

this.messagesService.addDialog({
message: "New Corner Dialog",
title: "Dialog Title"
buttonProps: [{ primary: true, text: "Accept", onClick: () => {alert("onClick")} }]
});

when click the button, the onClick does not response which cause whole page hang

Dashboard widget (ms.vss-dashboards-web.widget) error - No handler found on any channel for message

I'm trying to build a simple dashboard widget and I can't seem to get it working. I believe there's an issue with the library and how it registers dashboard widgets. Here's the code:

TestWidget.tsx

import * as React from "react";
import * as ReactDOM from "react-dom";
import { getAccessToken } from "azure-devops-extension-sdk";
import * as SDK from "azure-devops-extension-sdk";

interface IChartState {
  token: string;
  context: string;
}

class TestWidget extends React.Component<{}, IChartState> {
  constructor(props: {}) {
    super(props);
    this.state = {
      token: "",
      context: ""
    };
    this.getToken();

    SDK.init();
  }

  public componentDidMount() {
    console.log("mount");
  }

  public render(): JSX.Element {
    return <h1>I like waffles - asdf</h1>;
  }

  getToken = async (): Promise<void> => {
    const token = await getAccessToken();
    this.setState({ token: token });
  };
}

ReactDOM.render(<TestWidget />, document.getElementById("root"));

vss-extension.json

{
  "manifestVersion": 1,
  "version": "1.0.57",
  "name": "Fake widget",
  "description": "Fake widget",
  "publisher": "Ryan",
  "categories": ["Azure Repos"],
  "targets": [
    {
      "id": "Microsoft.VisualStudio.Services"
    }
  ],
  "content": {
    "details": {
      "path": "README.md"
    }
  },
  "icons": {
    "default": "img/world.png"
  },
  "files": [
    {
      "path": "dist",
      "addressable": true
    },
    {
      "path": "img",
      "addressable": true
    }
  ],
  "contributions": [
    {
      "id": "hello-world-hub-group",
      "type": "ms.vss-web.hub-group",
      "description": "Sample hub group",
      "targets": ["ms.vss-web.project-hub-groups-collection"],
      "properties": {
        "name": "Hello World!",
        "icon": {
          "dark": "img/world.png",
          "light": "img/world.png"
        }
      }
    },
    {
      "id": "default-hub",
      "type": "ms.vss-web.hub",
      "targets": [".hello-world-hub-group"],
      "properties": {
        "uri": "dist/hub/hub.html"
      }
    },
    {
      "id": "test-widget",
      "type": "ms.vss-dashboards-web.widget",
      "targets": ["ms.vss-dashboards-web.widget-catalog"],
      "properties": {
        "name": "AAA Test widget",
        "description": "AAA My Test",
        "catalogIconUrl": "img/logo.png",
        "previewImageUrl": "img/preview.png",
        "uri": "dist/test-widget/test-widget.html",
        "supportedSizes": [
          {
            "rowSpan": 2,
            "columnSpan": 2
          }
        ],
        "supportedScopes": ["project_team"]
      }
    }
  ],
  "scopes": ["vso.work"]
}

I end up with this error in the console: No handler found on any channel for message: {"id":1,"methodName":"","instanceId":"test-widget","params":null,"jsonrpc":"2.0"}

I suspect the handshake between my code and iframe isn't working correctly. I remember getting this handler error if you haven't registered your plugin (or you didn't use the right naming in vss-extension.json).

I continually get this image.
image

If I inspect the DOM the code shows up correctly, and I can even mount my component and print out the access token to console.

I flipped over to the old way to see if registering works correctly and it does. This code works, however I want to use the new SDK.

    <script src="lib/VSS.SDK.min.js"></script>

    <script type="text/javascript">
      VSS.init({
        explicitNotifyLoaded: true,
        usePlatformStyles: true
      });

      VSS.require(
        [
          "TFS/Dashboards/WidgetHelpers",
          "VSS/Service"
        ],
        function(WidgetHelpers, TFS_Wit_WebApi, VSS_Service) {
          WidgetHelpers.IncludeWidgetStyles();
          VSS.register("test-widget", function() {
            var projectId = VSS.getWebContext().project.id;

            return {
              load: function(widgetSettings) {
                return WidgetHelpers.WidgetStatusHelper.Success();
              },
              reload: function(widgetSettings) {
                return WidgetHelpers.WidgetStatusHelper.Success();
              }
            };
          });
          VSS.notifyLoadSucceeded();
        }
      );
    </script> 

I think that I've tried every combination of SDK.init() SDK.register() and setting SDK.init({loaded: false}) and calling SDK.notifyLoadSucceeded();

I'm currently splunking through https://github.com/microsoft/azure-devops-extension-sdk/blob/b5370ecc39c1e1c4b52f665a126bd2c21236ebca/src/SDK.ts, however I believe there's an issue within this library somewhere (for dashboard widgets at least).

I can actually hide the "Widget failed to load" by loading in the old SDK, registering the extension, and then use my React code behind it. But i know this is going to cause problems down the road when I want to build out and hook up the configuration panel.

I've been able to load the extensions here: https://github.com/microsoft/azure-devops-extension-sample without problems. Such as a hub widget. This seems to be just specific to dashboard widgets.

I'm currently running this: https://devblogs.microsoft.com/devops/streamlining-azure-devops-extension-development/ / https://github.com/microsoft/azure-devops-extension-hot-reload-and-debug - It works great for the hub widget that's in the project (no handler errors), however once I try and build a dashboard widget it throws the handler errors.

If someone is able to provide an example of this working with a dashboard widget (ms.vss-dashboards-web.widget) and preferably a config (ms.vss-dashboards-web.widget-configuration) you can hit birds with 1 stone, this issue, and this one in the sample repo: microsoft/azure-devops-extension-sample#8

How to Add button control

I have to add button and on click of the button need to show the pop-up window on work item page. Is it possible to achieve the same using extension?

How is this repo related to the vss-web-extension-sdk

I'm having some difficulties understanding how those repos are correlated. Official doku point to the vss-web-extension-sdk as SDK that should be used but on the other hand it looks like it is not maintained any more.
In vss-web-extension-sdk we had access to GUI control in this one no. What is the proper way of developing plugins? Can anyone here answer this question?

Can't publish

I cloned the repo, changed the publisher ID to my own, built, and then ran tfx extension create --manifest-globs azure-devops-extension.json

error: Your extension must define at least one contribution or contribution type.

`getUser` should never return undefined

Why does this return IUserContext | undefined? Shouldn't we always have a user?

/**
* Gets information about the current user
*/
export declare function getUser(): IUserContext | undefined;

No public API to get UI culture info

Problem: Need to support different languages (Russian, English and German) in a work item control extension.

There is no public API to get locale that configured in user profile.
Old VSS SDK had API for this info:

var culture = TFS.uiCulture.toLowerCase();

New SDK does not have public methods to get configured work item form UI culture info.

In azure-devops-ui there is a function to get current culture

import { getCurrentCulture } from "azure-devops-ui/Core/Util/Culture"

defined as

/**
 * Get culture settings for the current user's preferred culture
 */
export declare function getCurrentCulture(): ICultureInfo;

...but it just doesn't work and always returns invariant culture (en-US) regardless of configured UI culture.
Because if we look at JS code for this function, we see..

var currentCulture;
/**
 * Get culture settings for the current user's preferred culture
 */
export function getCurrentCulture() {
    if (!currentCulture) {
        currentCulture = getInvariantCulture();
    }
    return currentCulture;
}

...and module variable currentCulture is nowhere and never initialized, so function getCurrentCulture always returns invariant culture info.

So to solve business problem, I forced to resort to dirty hacks such as patching SDK script to retrieve configured culture from previously private "handshake info" provided to SDK.init function internally.

/*
* Dirty hack here! 
* SDK.getPageContext() isn't available, but a function injected in SDK module JavaScript source, and then patched 
* SDK module aliased in webpack pretending to be original azure-devops-extension-sdk module
*/
function getLocale(): string {
    return SDK.getPageContext()?.globalization?.culture;
}

Such dirty hacks for solving ordinary problems is not what we would like to have from the new SDK.

Azure DevOps - Internal and external comments

In my organization we are looking for a solution in Azure DevOps that would allow us to define which comments added to a work item would trigger a notification to a user who created the work item via email and does not have a license and in general access to Azure DevOps and which comments would not trigger a notification.
In tools like ZenDesk or Jira Service Desk these types of comments are called internal and external:

  • internal comments - trigger email received by people with access to Azure DevOps and are visible to everyone with access to project
  • external comments - trigger email received by everyone involved in the work item, people with access to project/Azure DevOps and people without access but added to the work item as e.g. creator or CCed.

What server versions are supported? (The registered object DevOps.HostControl could not be found.)

I don't see any docs on this yet...

We are on TFS 2017 Update 3.

When I rebuild and try the samples, after I change the category in the manifest to something recognized (TFS complains about the Pipelines category when I try to upload the .vsix to my on-prem), and add missing .html content types, I get the following:

image

It's trying to invokeRemoteMethod with a parameter of "Devops.HostControl", which i guess is something that's supposed to be on the server already? So this means my TFS is not supported?

parentChannel.invokeRemoteMethod<IExtensionHandshakeResult>("initialHandshake", hostControlId, [initOptions]).then((handshakeData) => {

Error calling the IWorkItemFormNavigationService on an on-premise

Dear,
I am running into an error on an on-premise instance of Azure DevOps 2019. The same extension installed on an online organization, is working fine.

This the source code (typescript):
const navigationService = await SDK.getService<IWorkItemFormNavigationService>(WorkItemTrackingServiceIds.WorkItemFormNavigationService); if (typeof navigationService != 'undefined' && navigationService != null) { navigationService.openWorkItem(id, false); } else { throw new Error("Could not load WorkItemFormNavigationService from the SDK"); }

It is failing on the call to .getService() with the following message:
`
message: "No contribution provider or uri for ms.vss-work-web.work-item-form-navigation-service."

stack: "Error: No contribution provider or uri for ms.vss-work-web.work-item-form-navigation-service.
at t.getBackgroundHost (https://myserver.be/tfs/_static/_ext/ms.vss-web/ext-content/ms.vss-web.ext-content.luCfz4YwcHM3_pJR.min.js:1:19120)
at t.getService (https://myserver.be/tfs/_static/_ext/ms.vss-web/ext-content/ms.vss-web.ext-content.luCfz4YwcHM3_pJR.min.js:1:18834)
at https://myserver.be/tfs/_static/_ext/ms.vss-web/platform-content/ms.vss-web.platform-content.xjg1YXj9NZN2H2LQ.min.js:1:21067"
`

I have found a temporary workaround that works (but not as nice as it should)
const commonNavigationService = await SDK.getService<IHostNavigationService>(CommonServiceIds.HostNavigationService); if (typeof commonNavigationService != 'undefined' && commonNavigationService != null) { console.warn("Could not load WorkItemFormNavigationService from the SDK. Workaround applied.") commonNavigationService.navigate(editUrl); } else { throw new Error("Could not load HostNavigationService from the SDK"); }
Can someone please take a look?

Thanks in advance.

Kr.
Edward Trouw

React 17 support by azure-devops-ui

As there is no clear public outlet for azure-devops-ui support, I will raise my question over here:

When adding azure-devops-ui to a newly created React 17 app I get the following error:

Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"^17.0.2" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.1" from [email protected]
npm ERR! node_modules/azure-devops-ui
npm ERR!   azure-devops-ui@"*" from the root project

So I guess I need to downgrade to React 16. Are there any short term plans to make the UI library compatible with React 17?
Or maybe even better, convert it to web components? In order to get it consumed by Blazor, Angular, Vue, etc.

Not build & release object in API

hello,

I would like to create a Hub typ extension to list and manage my builds and release.
But I can not find the API documentation "azure-devops-extension-sdk".
On the readme, the link to the API is in 404.

I can not find the objects to reach the builds + release must use another API.

Thank you

define is not a function

I'm trying to develop an extension for Azure DevOps. But whenever I try to use the SDK it pop an error in the console :

Uncaught TypeError: define is not a function

I've tried to manually add requestjs/requirejs but it still doesn't work

here is the little code that I use

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
    <div id="root"></div>
    <!-- <script src="./WorkItemFormPage.tsx" type="module"></script> -->
    <script type="module">
      import * as SDK from "azure-devops-extension-sdk";

      SDK.init();
    </script>
  </body>
</html>

If you need more details about the code, feel free to ask!

How to get an instance of GitRestClient?

I need to get an instance of the GitRestClient in my extension (Custom Work Item Control).
When I was using the "old" extension SDK I did the following:

import * as GitRestClient from "TFS/VersionControl/GitRestClient";
private gitClient: GitRestClient.GitHttpClient4_1;
this.gitClient = GitRestClient.getClient();

But I'm currently using the new SDK and want to stay on it. the getClient() method does not exist on the GitRestClient.
I'm importing the types as follows:
import {
GitRestClient,
GitVersionDescriptor,
GitVersionOptions,
GitVersionType,
VersionControlRecursionType,
} from "azure-devops-extension-api/Git";

But how do I get an instance of the GitRest Client?
I can see that there's a getClient in azure-devops-extension-api but it requires a RestClientFactory and it looks there's a default which calls the constructor with IVssRestClientOptions which would need to be passed.

As I said I would like to obtain an instance of the GitRestClient in my custom control to call some GitAPI's.

Thanks for your support.
Georg

Graph api missing listGroups

As far as I can tell there's no way to list out the groups with the new api like the listGroups() call in the old one. Without that there doesn't seem to be a way to lookup group names without already having a descriptor or scope ID.

Error when I execute `jest`

In my jest.config.js

module.exports = {
  projects: [
    './jest.config.test.js',
    './jest.config.eslint.js',
    './jest.config.firestore.js',
  ],
  transform: {
    // '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { rootMode: 'upward' }],
    '^.+\\.(ts|tsx)?$': 'ts-jest',
    '^.+\\.(js|jsx)$': 'babel-jest',
  },
  transformIgnorePatterns: [
    '/node_modules/(?!@hookform/*).+\\.[tj]sx?$',
    'node_modules/(?!(azure-devops-ui|azure-devops-extension-sdk)/)',
  ],
  watchPlugins: [
    'jest-watch-typeahead/filename',
    'jest-watch-typeahead/testname',
    'jest-watch-select-projects',
  ],
};

And my jest.config.test.js

module.exports = {
  displayName: 'test',
  rootDir: 'src/',
  clearMocks: true,
  errorOnDeprecated: true,
  testEnvironment: 'jsdom',
  coverageDirectory: '<rootDir>/../coverage/',
  collectCoverageFrom: ['<rootDir>/**/*.{ts,tsx}', '<rootDir>/**/*.{js,jsx}'],
  coveragePathIgnorePatterns: [
    '/node_modules/',
    '/__mocks__/',
    '/mocks/',
    '/@types/',
    '/public/',
  ],
  setupFilesAfterEnv: ['<rootDir>/../jest.setup.ts'],
  testMatch: ['<rootDir>/**/*.test.[tj]s?(x)'],
  notify: true,
  notifyMode: 'failure-change',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
  transformIgnorePatterns: [
    '/node_modules/(?!@hookform/*).+\\.[tj]sx?$',
    'node_modules/(?!(azure-devops-ui|azure-devops-extension-sdk)/)',
  ],
  preset: 'ts-jest/presets/js-with-ts',
  moduleNameMapper: {
    '@babel/core/lib/config/files/index-browser.js':
      '@babel/core/lib/config/files/index.js',
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
      '<rootDir>/__mocks__/fileMock.ts',
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
  },
};

image

Extensions updates on self-hosted build server (on-premise)

Have a self-hosted build server (Windows) and extensions are not updated automatically. For example, Extensions under Organization Settings shows API Management Suite version 3.5.1 installed whereas the job log shows that 3.3.1 was used and that is the latest version installed on-premise:

 C:\BuildAgent2\_work\_tasks\apim_fbb5ba7e-f837-4f46-b31e-f34c117fdd05\3.3.1\apim.ps1

Unsuccessful in finding info online how to force an update specifically on extensions for self-hosted agents. Checked the agent logs. Nothing (from the daily updates).

Tried running the release from a hosted (azure) agent. Same 3.3.1 version is used. Unclear why the organization wide log over extensions shows 3.5.1 but 3.3.1 is used both self-hosted and Azure hosted.

Bookmarking a 'tab' that is added by an extension does not work

Hi,
I have created an extension, that adds a custom tab (type: ms.vss-web.tab) to the queryresults page (targets: ms.vss-work-web.query-tabs). Everything is working fine... except when I try to bookmark the tab.

I am just copying the url, that is something like this: https://XYZ/_queries/mypublisherid.mycontributionid/query-guid/

When I close the browser and try to use the bookmark... it doesnt work. It just opens the queryresults page.
At first it looks like that this is a loading issue... the custom appears after a second when everything else is loaded. So I have tried to optimize everything at my end.

But I also tried the following...

I have closed the browser
Opened it with the bookmark... it shows the query results page (that is not the expected result)
I am waiting untill the tab has appeared (so everything is loaded)
I am re-using the bookmark... but this also results into the query results page (that was something I really didnt expect)
It only seems to work whenever I have had opened the custom tab itself, within the browser session. Once I have done this, using bookmarks (like within the teamprojects homepage wiki) is no problem.

But I want to be able to bookmark it and save it as a favourite within my browser... or be able to sent someone the url by email.

Unfortunately this seems to be not possible.

I am using the new API.

The samples from the old VSS api... the contribution guide... seems to be able to do this without any problems.

So I am hoping you could help me out.

Kr
Edward

Get host URL

In the old VSS SDK it was possible to retrieve the host URL easily but I can't find a way to do that with this new SDK. I suppose it's something that could easily be added to the object returned by SDK.getHost()?

This is useful since extensions run in iframes and sometimes we need to refer to the host URL. For example, I'm currently struggling to render a user avatar. The identity API returns a relative URL for the avatar and we need to append the host to it in order to render the image correctly in the iFrame.

I appreciate any guidance or having my suggestion accepted and added to the SDK.

Thanks.

Work Item form does not resize when DropDown control is used

I created a very basic custom control that implements the DropDown control from azure-devops-ui. When the DropDown control is clicked, the form does not adjust so the contents are not visible - the drop down list is obscured by the fields on the work item form below it:

image

I tried calling the SDK resize method in various places but have not been able to get the form to resize.

I implemented a similar control with the older VSS SDK which does resize correctly, but the older SDK does not honor the themes used in AzDo so I need to use the newer SDK.

My repo (ignore the readme, I used the control sample repo as a starting point): https://github.com/jonvest/azure-devops-dropdown

User ID from SDK.getAppToken() doesn't match the user ID from other Azure APIs

Hi there,

I use the following code to get the user token and validate their requests on the backend. This token has a user_id property that identifies the user:

import * as SDK from 'azure-devops-extension-sdk';
const token = await SDK.getAppToken();

Additionally, I use other methods to build user pickers and render user names on the screen such as:

import { getService } from 'azure-devops-extension-sdk';
import { IdentityServiceIds } from 'azure-devops-extension-api/Identities';

const identityService = await getService(IdentityServiceIds.IdentityService);
identityService.searchIdentitiesAsync(userId, ['user'], undefined, 'uid');
identityService.getIdentityMruAsync();
identityService.searchIdentitiesAsync(query, ['user']);

The problem is that the users returned by the methods above don’t have the same ID as the ID present in the appToken in some Azure DevOps instances. This causes a huge problem because I can’t find the logged-in user within the API query results, causing a lot of other issues.

The fun fact is that I have 3 Azure DevOps Services instances, in which I have the same set of users, and this problem only happens with some of these user/instance combinations.

What's the difference between vss-web-extension-sdk and azure-devops-extension-sdk?

The ReadMe for both the projects - vss-web-extension-sdk and azure-devops-exntension-sdk - say that they are client SDK for developing extensions for VSTS (now Azure Devops).

Why are they two different SDKs ? What's the difference? And what is the recommendation if I'm writing a new extension? Which one should I use?

Sadly I couldn't find any documentation explaining the above

Ref: microsoft/vss-web-extension-sdk#149

Custom Forms Control is missing the user descriptor on `SDK.getUser()`

In our custom form controls we noticed that the member IUserContext.descriptor is somehow missing from the SDK.getUser() object.
We want to use the descriptor to get membership information from the API of the current user (for a UI-only block).

What we do get is an object similar to this:

{
  displayName: "Full Name",
  id: "0000000-0000-1000-0000-000000000000",
  imageUrl: "https://dev.azure.com/<instance>/_apis/GraphProfile/MemberAvatars/aad.MDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA=",
  name: "[email protected]"
}

As our extension has different contributions, we can see that on others (for example a project/organization settings page contributions) we get the descriptor:

{
  descriptor: "aad.MDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA=",
  displayName: "Full Name",
  id: "0000000-0000-1000-0000-000000000000",
  imageUrl: "https://dev.azure.com/<instance>/_apis/GraphProfile/MemberAvatars/aad.MDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA=",
  name: "[email protected]"
}

However, it seems to be missing on custom form controls...

As this is not documented (the TypeScript type says the field is always there) and I don't see any other good way, I assume this is a Bug. We could:

  • parse imageUrl
  • compare the data with the full list of users) to get the current user context.
  • creating the descriptor ourself from the id-entry but for some reason the Ids differ (as in the anonymized example above).

We would love to hear a workaround or an alternative approach to solve the problem at hand with the SDK or other REST calls.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.