Lägga till en instrumentpanelswidget
Azure DevOps Services | Azure DevOps Server 2022 – Azure DevOps Server 2019
Widgetar på en instrumentpanel implementeras som bidrag i tilläggsramverket. Ett enda tillägg kan ha flera bidrag. Lär dig hur du skapar ett tillägg med flera widgetar som bidrag.
Den här artikeln är uppdelad i tre delar, var och en bygger på föregående - börjar med en enkel widget och slutar med en omfattande widget.
Dricks
Läs vår senaste dokumentation om tilläggsutveckling med hjälp av Azure DevOps Extension SDK.
Förutsättningar
- Kunskap: Viss kunskap om JavaScript, HTML, CSS krävs för widgetutveckling.
- En organisation i Azure DevOps.
- En textredigerare. I många av självstudierna använder vi Visual Studio Code.
- Den senaste versionen av noden.
- Plattformsoberoende CLI för Azure DevOps (tfx-cli) för att paketera dina tillägg.
- tfx-cli kan installeras med ,
npm
en komponent i Node.js genom att köranpm i -g tfx-cli
- tfx-cli kan installeras med ,
- En hemkatalog för projektet. Den här katalogen kallas för
home
hela självstudien.
Filstruktur för tillägg:
|--- README.md
|--- sdk
|--- node_modules
|--- scripts
|--- VSS.SDK.min.js
|--- img
|--- logo.png
|--- scripts
|--- hello-world.html // html page to be used for your widget
|--- vss-extension.json // extension's manifest
I den här självstudien
- Del 1: Visar hur du skapar en ny widget som skriver ut ett enkelt "Hello World"-meddelande.
- Del 2: Bygger på den första delen genom att lägga till ett anrop till ett Azure DevOps REST API.
- Del 3: Förklarar hur du lägger till konfiguration i widgeten.
Kommentar
Om du har bråttom och vill lägga händerna på koden direkt kan du ladda ned exemplen.
När du har laddat ned går du till widgets
mappen och följer sedan steg 6 och steg 7 direkt för att publicera exempeltillägget som har de tre exempelwidgetarna med varierande komplexitet.
Kom igång med några grundläggande format för widgetar som vi tillhandahåller out-of-the-box och lite vägledning om widgetstruktur.
Del 1: Hello World
Del 1 visar en widget som skriver ut "Hello World" med JavaScript.
Steg 1: Hämta klient-SDK: VSS.SDK.min.js
SDK-kärnskriptet VSS.SDK.min.js
gör det möjligt för webbtillägg att kommunicera med värdens Azure DevOps-ram. Skriptet utför åtgärder som att initiera, meddela att tillägget läses in eller få kontext om den aktuella sidan.
Hämta Client SDK-filen VSS.SDK.min.js
och lägg till den i webbappen. Placera den i home/sdk/scripts
mappen.
Om du vill hämta SDK:n använder du kommandot "npm install":
npm install vss-web-extension-sdk
Mer information finns på GitHub-sidan för Klient-SDK.
Steg 2: Konfigurera HTML-sidan – hello-world.html
HTML-sidan är limmet som håller ihop layouten och innehåller referenser till CSS och JavaScript. Du kan ge filen namnet vad som helst. Uppdatera alla referenser till hello-world
med det namn du använder.
Widgeten är HTML-baserad och finns i en iframe.
Lägg till följande HTML i hello-world.html
. Vi lägger till den obligatoriska referensen till VSS.SDK.min.js
filen och inkluderar ett h2
element som uppdateras med strängen Hello World i det kommande steget.
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
</div>
</body>
</html>
Även om vi använder en HTML-fil ignoreras de flesta andra HTML-huvudelement än skript och länkar av ramverket.
Steg 3: Uppdatera JavaScript
Vi använder JavaScript för att återge innehåll i widgeten. I den här artikeln omsluter vi all JavaScript-kod i ett <script>
element i HTML-filen. Du kan välja att ha den här koden i en separat JavaScript-fil och referera till den i HTML-filen.
Koden renderar innehållet. Den här JavaScript-koden initierar även VSS SDK, mappar koden för widgeten till ditt widgetnamn och meddelar tilläggsramverket för widgetframgångar eller -fel.
I vårt fall skriver följande kod ut "Hello World" i widgeten. Lägg till det här script
elementet head
i HTML-koden.
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require("TFS/Dashboards/WidgetHelpers", function (WidgetHelpers) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget", function () {
return {
load: function (widgetSettings) {
var $title = $('h2.title');
$title.text('Hello World');
return WidgetHelpers.WidgetStatusHelper.Success();
}
};
});
VSS.notifyLoadSucceeded();
});
</script>
VSS.init
initierar handskakningen mellan den iframe som är värd för widgeten och värdramen.- Vi skickar
explicitNotifyLoaded: true
så att widgeten uttryckligen kan meddela värden när den är klar med inläsningen. Med den här kontrollen kan vi meddela att belastningen har slutförts efter att de beroende modulerna har lästs in. Vi skickarusePlatformStyles: true
så att widgeten kan använda Azure DevOps-kärnformat för HTML-element (till exempel brödtext, div och så vidare). Om widgeten föredrar att inte använda dessa formatmallar kan de skicka inusePlatformStyles: false
. VSS.require
används för att läsa in de vss-skriptbibliotek som krävs. Ett anrop till den här metoden läser automatiskt in allmänna bibliotek som JQuery och JQueryUI. I vårt fall är vi beroende av WidgetHelpers-biblioteket, som används för att kommunicera widgetstatus till widgetramverket. Därför skickar vi motsvarande modulnamnTFS/Dashboards/WidgetHelpers
och ett återanrop tillVSS.require
. Återanropet anropas när modulen har lästs in. Återanropet har resten av JavaScript-koden som behövs för widgeten. I slutet av återanropet anroparVSS.notifyLoadSucceeded
vi för att meddela att belastningen har slutförts.WidgetHelpers.IncludeWidgetStyles
innehåller en formatmall med några grundläggande css för att komma igång. Om du vill använda dessa formatmallar omsluter du innehållet i ett HTML-element med klassenwidget
.VSS.register
används för att mappa en funktion i JavaScript, som unikt identifierar widgeten bland de olika bidragen i tillägget. Namnet ska matchaid
det som identifierar ditt bidrag enligt beskrivningen i steg 5. För widgetar ska funktionen som skickas tillVSS.register
returnera ett objekt som uppfyllerIWidget
kontraktet, till exempel att det returnerade objektet ska ha en inläsningsegenskap vars värde är en annan funktion som har kärnlogik för att återge widgeten. I vårt fall är det att uppdatera texten i elementeth2
till "Hello World". Det är den här funktionen som anropas när widgetramverket instansierar din widget. Vi använderWidgetStatusHelper
från WidgetHelpers för att returneraWidgetStatus
som framgång.
Varning
Om namnet som används för att registrera widgeten inte matchar ID:t för bidraget i manifestet fungerar widgeten oväntat.
vss-extension.json
bör alltid finnas i mappens rot (i den här guiden).HelloWorld
För alla andra filer kan du placera dem i vilken struktur du vill i mappen. Se bara till att uppdatera referenserna på rätt sätt i HTML-filerna och i manifestetvss-extension.json
.
Steg 4: Uppdatera tilläggslogotypen: logo.png
Logotypen visas på Marketplace och i widgetkatalogen när en användare installerar tillägget.
Du behöver en katalogikon på 98 x 98 px. Välj en bild, ge den logo.png
namnet och placera den img
i mappen.
Du kan namnge dessa bilder, men du vill så länge tilläggsmanifestet i nästa steg uppdateras med de namn som du använder.
Steg 5: Skapa tilläggsmanifestet: vss-extension.json
Varje tillägg måste ha en tilläggsmanifestfil.
- Läs referensen för tilläggsmanifestet.
- Läs mer om bidragspunkterna i Utökningspunkter.
- Skapa en json-fil (
vss-extension.json
till exempel) ihome
katalogen med följande innehåll:
{
"manifestVersion": 1,
"id": "azure-devops-extensions-myExtensions",
"version": "1.0.0",
"name": "My First Set of Widgets",
"description": "Samples containing different widgets extending dashboards",
"publisher": "fabrikam",
"categories": ["Azure Boards"],
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"icons": {
"default": "img/logo.png"
},
"contributions": [
{
"id": "HelloWorldWidget",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog"
],
"properties": {
"name": "Hello World Widget",
"description": "My first widget",
"catalogIconUrl": "img/CatalogIcon.png",
"previewImageUrl": "img/preview.png",
"uri": "hello-world.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
}
],
"files": [
{
"path": "hello-world.html",
"addressable": true
},
{
"path": "sdk/scripts",
"addressable": true
},
{
"path": "img",
"addressable": true
}
]
}
Mer information om obligatoriska attribut finns i tilläggsmanifestreferensen.
Kommentar
Ändra utgivaren till ditt utgivarnamn. Information om hur du skapar en utgivare finns i Paket/Publicera/Installera.
Ikoner
Ikonernas strof anger sökvägen till tilläggets ikon i manifestet.
Bidrag
Varje bidragspost definierar egenskaper.
- ID :t för att identifiera ditt bidrag. Det här ID:t bör vara unikt i ett tillägg. Det här ID:t ska matcha det namn som du använde i steg 3 för att registrera widgeten.
- Typ av bidrag. För alla widgetar ska typen vara
ms.vss-dashboards-web.widget
. - Matrisen med mål som bidraget bidrar till. För alla widgetar ska målet vara
[ms.vss-dashboards-web.widget-catalog]
. - Egenskaperna är objekt som innehåller egenskaper för bidragstypen. För widgetar är följande egenskaper obligatoriska.
Property | Beskrivning |
---|---|
name | Namnet på widgeten som ska visas i widgetkatalogen. |
description | Beskrivning av widgeten som ska visas i widgetkatalogen. |
catalogIconUrl | Relativ sökväg till katalogikonen som du lade till i steg 4 för att visa i widgetkatalogen. Bilden ska vara 98 px x 98 px. Om du har använt en annan mappstruktur eller ett annat filnamn anger du lämplig relativ sökväg här. |
previewImageUrl | Relativ sökväg för den förhandsgranskningsbild som du lade till i steg 4 för att visa i widgetkatalogen. Bilden ska vara 330 px x 160 px. Om du har använt en annan mappstruktur eller ett annat filnamn anger du lämplig relativ sökväg här. |
uri | Relativ sökväg för HTML-filen som du lade till i steg 1. Om du har använt en annan mappstruktur eller ett annat filnamn anger du lämplig relativ sökväg här. |
supportedSizes | Matris med storlekar som stöds av widgeten. När en widget stöder flera storlekar är den första storleken i matrisen standardstorleken för widgeten. widget size anges för de rader och kolumner som används av widgeten i instrumentpanelens rutnät. En rad/kolumn motsvarar 160 px. Alla dimensioner som är större än 1 x 1 får 10 px extra som representerar rännstenen mellan widgetar. Till exempel är 160*3+10*2 en 3x2-widget bred och 160*2+10*1 lång. Den maximala storleken som stöds är 4x4 . |
supportedScopes | För närvarande stöds endast teaminstrumentpaneler. Värdet måste vara project_team . Framtida uppdateringar kan innehålla fler alternativ för instrumentpanelsomfång. |
Filer
I filens strof står de filer som du vill inkludera i paketet – HTML-sidan, skripten, SDK-skriptet och logotypen.
Ange addressable
till true
såvida du inte inkluderar andra filer som inte behöver vara URL-adresserbara.
Kommentar
Mer information om tilläggsmanifestfilen, till exempel dess egenskaper och vad de gör, finns i referensen för tilläggsmanifestet.
Steg 6: Paketera, publicera och dela
När du har ditt skriftliga tillägg är nästa steg mot att få det till Marketplace att paketera alla dina filer tillsammans. Alla tillägg paketeras som VSIX 2.0-kompatibla .vsix-filer – Microsoft tillhandahåller ett plattformsoberoende kommandoradsgränssnitt (CLI) för att paketera tillägget.
Hämta förpackningsverktyget
Du kan installera eller uppdatera plattformsoberoende CLI för Azure DevOps (tfx-cli) med hjälp npm
av , en komponent i Node.js, från kommandoraden.
npm i -g tfx-cli
Paketera tillägget
Det går inte att paketera tillägget i en .vsix-fil när du har tfx-cli. Gå till tilläggets hemkatalog och kör följande kommando.
tfx extension create --manifest-globs vss-extension.json
Kommentar
En tilläggs-/integrationsversion måste ökas vid varje uppdatering.
När du uppdaterar ett befintligt tillägg uppdaterar du antingen versionen i manifestet eller skickar kommandoradsväxeln --rev-version
. Detta ökar uppdateringsversionsnumret för tillägget och sparar den nya versionen i manifestet.
När du har paketerade tillägget i en .vsix-fil är du redo att publicera tillägget på Marketplace.
Skapa utgivare för tillägget
Alla tillägg, inklusive tillägg från Microsoft, identifieras som tillhandahållna av en utgivare. Om du inte redan är medlem i en befintlig utgivare skapar du en.
- Logga in på Visual Studio Marketplace-publiceringsportalen
- Om du inte redan är medlem i en befintlig utgivare måste du skapa en utgivare. Om du redan har en utgivare bläddrar du till och väljer Publicera tillägg under Relaterade webbplatser.
- Ange en identifierare för utgivaren, till exempel:
mycompany-myteam
- Identifieraren används som värde för
publisher
attributet i tilläggens manifestfil.
- Identifieraren används som värde för
- Ange ett visningsnamn för utgivaren, till exempel:
My Team
- Ange en identifierare för utgivaren, till exempel:
- Granska Marketplace Publisher-avtalet och välj Skapa.
Nu har utgivaren definierats. I en framtida version kan du bevilja behörighet att visa och hantera utgivarens tillägg.
Publiceringstillägg under en gemensam utgivare förenklar processen för team och organisationer och erbjuder en säkrare metod. Den här metoden eliminerar behovet av att distribuera en enda uppsättning autentiseringsuppgifter mellan flera användare, vilket förbättrar säkerheten och
vss-extension.json
Uppdatera manifestfilen i exemplen för att ersätta utgivar-IDfabrikam
:t för dummy med ditt utgivar-ID.
Publicera och dela tillägget
Nu kan du ladda upp ditt tillägg till Marketplace.
Välj Ladda upp nytt tillägg, gå till den paketerade .vsix-filen och välj Ladda upp.
Du kan också ladda upp tillägget via kommandoraden tfx extension publish
genom att använda kommandot i stället för tfx extension create
att paketera och publicera tillägget i ett steg.
Du kan också använda --share-with
för att dela tillägget med ett eller flera konton efter publiceringen.
Du behöver också en personlig åtkomsttoken.
tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization
Steg 7: Lägg till widget från katalogen
Logga in på projektet.
http://dev.azure.com/{Your_Organization}/{Your_Project}
Välj Översiktsinstrumentpaneler>.
Välj Lägg till en widget.
Markera widgeten och välj sedan Lägg till.
Widgeten visas på instrumentpanelen.
Del 2: Hello World med Azure DevOps REST API
Widgetar kan anropa någon av REST-API:erna i Azure DevOps för att interagera med Azure DevOps-resurser. I följande exempel använder vi REST API för WorkItemTracking för att hämta information om en befintlig fråga och visa viss frågeinformation i widgeten under texten "Hello World".
Steg 1: Lägg till HTML-fil
Kopiera filen hello-world.html
från föregående exempel och byt namn på kopian till hello-world2.html
. Mappen ser nu ut som i följande exempel:
|--- README.md |--- node_modules
|--- SDK
|--- skript |--- VSS. SDK.min.js |--- img |--- logo.png |--- skript
|--- hello-world.html // html-sida som ska användas för widgeten |--- hello-world2.html // omdöpt kopia av hello-world.html |--- vss-extension.json // tilläggets manifest
Om du vill lagra frågeinformationen lägger du till ett nytt div
element under h2
.
Uppdatera namnet på widgeten från HelloWorldWidget
till HelloWorldWidget2
på raden där du anropar VSS.register
.
Med den här åtgärden kan ramverket unikt identifiera widgeten i tillägget.
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require("TFS/Dashboards/WidgetHelpers", function (WidgetHelpers) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget2", function () {
return {
load: function (widgetSettings) {
var $title = $('h2.title');
$title.text('Hello World');
return WidgetHelpers.WidgetStatusHelper.Success();
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
<div id="query-info-container"></div>
</div>
</body>
</html>
Steg 2: Få åtkomst till Azure DevOps-resurser
Om du vill aktivera åtkomst till Azure DevOps-resurser måste omfång anges i tilläggsmanifestet . Vi lägger till omfånget i vso.work
vårt manifest.
Det här omfånget anger att widgeten behöver skrivskyddad åtkomst till frågor och arbetsobjekt. Se alla tillgängliga omfång här.
Lägg till följande kod i slutet av tilläggsmanifestet.
{
"scopes":[
"vso.work"
]
}
Om du vill inkludera andra egenskaper bör du uttryckligen ange dem, till exempel:
{
"name": "example-widget",
"publisher": "example-publisher",
"version": "1.0.0",
"scopes": [
"vso.work"
]
}
Varning
Det finns för närvarande inte stöd för att lägga till eller ändra omfång efter publicering av ett tillägg. Om du redan har laddat upp tillägget tar du bort det från Marketplace. Gå till Visual Studio Marketplace-publiceringsportalen, högerklicka på tillägget och välj Ta bort.
Steg 3: Gör REST API-anropet
Det finns många bibliotek på klientsidan som kan nås via SDK för att göra REST API-anrop i Azure DevOps. Dessa bibliotek kallas REST-klienter och är JavaScript-omslutningar runt Ajax-anrop för alla tillgängliga slutpunkter på serversidan. Du kan använda metoder som tillhandahålls av dessa klienter i stället för att skriva Ajax-anrop själv. Dessa metoder mappar API-svaren till objekt som koden kan använda.
I det här steget uppdaterar vi anropet VSS.require
för att läsa in AzureDevOps/WorkItemTracking/RestClient
, som tillhandahåller REST-klienten WorkItemTracking.
Vi kan använda den här REST-klienten för att hämta information om en fråga som heter Feedback
under mappen Shared Queries
.
Inuti funktionen som vi skickar till VSS.register
skapar vi en variabel för att lagra det aktuella projekt-ID:t. Vi behöver den här variabeln för att hämta frågan.
Vi skapar också en ny metod getQueryInfo
för att använda REST-klienten. Den här metoden som sedan anropas från inläsningsmetoden.
Metoden getClient
ger en instans av REST-klienten som vi behöver.
Metoden getQuery
returnerar frågan omsluten i ett löfte.
Den uppdaterade VSS.require
ser ut så här:
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"],
function (WidgetHelpers, TFS_Wit_WebApi) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget2", function () {
var projectId = VSS.getWebContext().project.id;
var getQueryInfo = function (widgetSettings) {
// Get a WIT client to make REST calls to Azure DevOps Services
return TFS_Wit_WebApi.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Do something with the query
return WidgetHelpers.WidgetStatusHelper.Success();
}, function (error) {
return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
});
}
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
Observera användningen av felmetoden från WidgetStatusHelper
.
Det gör att du kan ange för widgetramverket att ett fel uppstod och dra nytta av den standardfelupplevelse som tillhandahålls till alla widgetar.
Om du inte har Feedback
frågan under Shared Queries
mappen ersätter Shared Queries\Feedback
du i koden med sökvägen till en fråga som finns i projektet.
Steg 4: Visa svaret
Det sista steget är att återge frågeinformationen i widgeten.
Funktionen getQuery
returnerar ett objekt av typen Contracts.QueryHierarchyItem
inuti ett löfte.
I det här exemplet visar vi fråge-ID, frågenamn och namnet på frågeskapare under texten "Hello World".
Ersätt kommentaren // Do something with the query
med följande kod:
// Create a list with query details
var $list = $('<ul>');
$list.append($('<li>').text("Query Id: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));
// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
Din sista hello-world2.html
är som i följande exempel:
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"],
function (WidgetHelpers, TFS_Wit_WebApi) {
WidgetHelpers.IncludeWidgetStyles();
VSS.register("HelloWorldWidget2", function () {
var projectId = VSS.getWebContext().project.id;
var getQueryInfo = function (widgetSettings) {
// Get a WIT client to make REST calls to Azure DevOps Services
return TFS_Wit_WebApi.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Create a list with query details
var $list = $('<ul>');
$list.append($('<li>').text("Query ID: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));
// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
// Use the widget helper and return success as Widget Status
return WidgetHelpers.WidgetStatusHelper.Success();
}, function (error) {
// Use the widget helper and return failure as Widget Status
return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
});
}
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
<div id="query-info-container"></div>
</div>
</body>
</html>
Steg 5: Uppdatera tilläggsmanifest
I det här steget uppdaterar vi tilläggsmanifestet så att det innehåller en post för vår andra widget.
Lägg till ett nytt bidrag till matrisen contributions
i egenskapen och lägg till den nya filen hello-world2.html
i matrisen i filegenskapen.
Du behöver en annan förhandsgranskningsbild för den andra widgeten. Namnge detta preview2.png
och placera det i img
mappen.
{
...,
"contributions": [
...,
{
"id": "HelloWorldWidget2",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog"
],
"properties": {
"name": "Hello World Widget 2 (with API)",
"description": "My second widget",
"previewImageUrl": "img/preview2.png",
"uri": "hello-world2.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
}
],
"files": [
{
"path": "hello-world.html",
"addressable": true
},
{
"path": "hello-world2.html",
"addressable": true
},
{
"path": "sdk/scripts",
"addressable": true
},
{
"path": "img",
"addressable": true
}
],
"scopes": [
"vso.work"
]
}
Steg 6: Paketera, publicera och dela
Paketera, publicera och dela tillägget. Om du redan har publicerat tillägget kan du packa om tillägget och uppdatera det direkt till Marketplace.
Steg 7: Lägg till widget från katalogen
Gå nu till din teaminstrumentpanel på https:\//dev.azure.com/{Your_Organization}/{Your_Project}
. Om den här sidan redan är öppen uppdaterar du den.
Hovra på Redigera och välj Lägg till. Widgetkatalogen öppnas där du hittar widgeten som du har installerat.
Om du vill lägga till den på instrumentpanelen väljer du widgeten och väljer Lägg till.
Del 3: Konfigurera Hello World
I del 2 av den här guiden såg du hur du skapar en widget som visar frågeinformation för en hårdkodad fråga. I den här delen lägger vi till möjligheten att konfigurera frågan som ska användas i stället för den hårdkodade. När användaren är i konfigurationsläge visas en liveförhandsgranskning av widgeten baserat på deras ändringar. Ändringarna sparas i widgeten på instrumentpanelen när användaren väljer Spara.
Steg 1: Lägg till HTML-fil
Implementeringar av widgetar och widgetkonfigurationer är mycket lika. Båda implementeras i tilläggsramverket som bidrag. Båda använder samma SDK-fil, VSS.SDK.min.js
. Båda baseras på HTML, JavaScript och CSS.
Kopiera filen html-world2.html
från föregående exempel och byt namn på kopian till hello-world3.html
. Lägg till en annan HTML-fil med namnet configuration.html
.
Mappen ser nu ut som i följande exempel:
|--- README.md
|--- sdk
|--- node_modules
|--- scripts
|--- VSS.SDK.min.js
|--- img
|--- logo.png
|--- scripts
|--- configuration.html
|--- hello-world.html // html page to be used for your widget
|--- hello-world2.html // renamed copy of hello-world.html
|--- hello-world3.html // renamed copy of hello-world2.html
|--- vss-extension.json // extension's manifest
Lägg till följande HTML i configuration.html
. Vi lägger i princip till den obligatoriska referensen VSS.SDK.min.js
till filen och ett select
element för listrutan för att välja en fråga från en förinställd lista.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
</head>
<body>
<div class="container">
<fieldset>
<label class="label">Query: </label>
<select id="query-path-dropdown" style="margin-top:10px">
<option value="" selected disabled hidden>Please select a query</option>
<option value="Shared Queries/Feedback">Shared Queries/Feedback</option>
<option value="Shared Queries/My Bugs">Shared Queries/My Bugs</option>
<option value="Shared Queries/My Tasks">Shared Queries/My Tasks</option>
</select>
</fieldset>
</div>
</body>
</html>
Steg 2: Konfigurera JavaScript
Använd JavaScript för att återge innehåll i widgetkonfigurationen precis som vi gjorde för widgeten i steg 3 i del 1 i den här guiden.
Den här JavaScript-koden renderar innehåll, initierar VSS SDK, mappar koden för widgetkonfigurationen till konfigurationsnamnet och skickar konfigurationsinställningarna till ramverket. I vårt fall läser följande kod in widgetkonfigurationen.
Öppna filen configuration.html
och följande <script>
element i <head>
.
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
VSS.register("HelloWorldWidget.Configuration", function () {
var $queryDropdown = $("#query-path-dropdown");
return {
load: function (widgetSettings, widgetConfigurationContext) {
var settings = JSON.parse(widgetSettings.customSettings.data);
if (settings && settings.queryPath) {
$queryDropdown.val(settings.queryPath);
}
return WidgetHelpers.WidgetStatusHelper.Success();
},
onSave: function() {
var customSettings = {
data: JSON.stringify({
queryPath: $queryDropdown.val()
})
};
return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
VSS.init
,VSS.require
ochVSS.register
spelar samma roll som de spelade för widgeten enligt beskrivningen i del 1. Den enda skillnaden är att för widgetkonfigurationer ska funktionen som skickas tillVSS.register
returnera ett objekt som uppfyllerIWidgetConfiguration
kontraktet.- Kontraktets
load
IWidgetConfiguration
egenskap bör ha en funktion som värde. Den här funktionen har en uppsättning steg för att återge widgetkonfigurationen. I vårt fall är det att uppdatera det valda värdet för listruteelementet med eventuella befintliga inställningar. Den här funktionen anropas när ramverket instansierar dinwidget configuration
- Kontraktets
onSave
IWidgetConfiguration
egenskap bör ha en funktion som värde. Den här funktionen anropas av ramverket när användaren väljer Spara i konfigurationsfönstret. Om användarens indata är redo att sparas serialiserar du det till en sträng, bildarcustom settings
objektet och använderWidgetConfigurationSave.Valid()
för att spara användarindata.
I den här guiden använder vi JSON för att serialisera användarens indata till en sträng. Du kan välja något annat sätt att serialisera användarens indata till strängen.
Den är tillgänglig för widgeten via objektets customSettings-egenskap WidgetSettings
.
Widgeten måste deserialisera, vilket beskrivs i steg 4.
Steg 3: JavaScript – aktivera liveförhandsgranskning
Om du vill aktivera live-förhandsgranskningsuppdatering när användaren väljer en fråga i listrutan bifogar vi en ändringshändelsehanterare till knappen. Den här hanteraren meddelar det ramverk som konfigurationen ändrade.
Den skickar även den customSettings
som ska användas för att uppdatera förhandsversionen. För att meddela ramverket notify
måste metoden anropas widgetConfigurationContext
. Det tar två parametrar, namnet på händelsen, som i det här fallet är WidgetHelpers.WidgetEvent.ConfigurationChange
, och ett EventArgs
objekt för händelsen, som skapats customSettings
från med hjälp av WidgetEvent.Args
hjälpmetoden.
Lägg till följande kod i funktionen som tilldelats egenskapen load
.
$queryDropdown.on("change", function () {
var customSettings = {
data: JSON.stringify({
queryPath: $queryDropdown.val()
})
};
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
widgetConfigurationContext.notify(eventName, eventArgs);
});
Reviderad: Se till att ramverket meddelas om konfigurationsändringen minst en gång för att aktivera knappen Spara .
I slutet ser ditt configuration.html
ut som i följande exempel:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
VSS.register("HelloWorldWidget.Configuration", function () {
var $queryDropdown = $("#query-path-dropdown");
return {
load: function (widgetSettings, widgetConfigurationContext) {
var settings = JSON.parse(widgetSettings.customSettings.data);
if (settings && settings.queryPath) {
$queryDropdown.val(settings.queryPath);
}
$queryDropdown.on("change", function () {
var customSettings = {data: JSON.stringify({queryPath: $queryDropdown.val()})};
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
widgetConfigurationContext.notify(eventName, eventArgs);
});
return WidgetHelpers.WidgetStatusHelper.Success();
},
onSave: function() {
var customSettings = {data: JSON.stringify({queryPath: $queryDropdown.val()})};
return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings);
}
}
});
VSS.notifyLoadSucceeded();
});
</script>
</head>
<body>
<div class="container">
<fieldset>
<label class="label">Query: </label>
<select id="query-path-dropdown" style="margin-top:10px">
<option value="" selected disabled hidden>Please select a query</option>
<option value="Shared Queries/Feedback">Shared Queries/Feedback</option>
<option value="Shared Queries/My Bugs">Shared Queries/My Bugs</option>
<option value="Shared Queries/My Tasks">Shared Queries/My Tasks</option>
</select>
</fieldset>
</div>
</body>
</html>
Steg 4: Implementera omläsning i widgeten – JavaScript
Vi konfigurerar widgetkonfiguration för att lagra den frågesökväg som användaren har valt.
Nu måste vi uppdatera koden i widgeten för att använda den här lagrade konfigurationen i stället för den hårdkodade Shared Queries/Feedback
från föregående exempel.
Öppna filen hello-world3.html
och uppdatera namnet på widgeten från HelloWorldWidget2
till HelloWorldWidget3
på raden där du anropar VSS.register
.
Med den här åtgärden kan ramverket unikt identifiera widgeten i tillägget.
Funktionen som mappas till HelloWorldWidget3
via VSS.register
returnerar för närvarande ett objekt som uppfyller IWidget
kontraktet.
Eftersom vår widget nu behöver konfiguration måste den här funktionen uppdateras för att returnera ett objekt som uppfyller IConfigurableWidget
kontraktet.
Det gör du genom att uppdatera retursatsen så att den innehåller en egenskap som kallas reload enligt följande kod. Värdet för den här egenskapen är en funktion som anropar getQueryInfo
metoden en gång till.
Den här omläsningsmetoden anropas av ramverket varje gång användarens indata ändras för att visa liveförhandsgranskningen. Den här omläsningsmetoden anropas också när konfigurationen sparas.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
return getQueryInfo(widgetSettings);
}
}
Den hårdkodade frågesökvägen i getQueryInfo
bör ersättas med den konfigurerade frågesökvägen, som kan extraheras från parametern widgetSettings
som skickas till metoden.
Lägg till följande kod i början av getQueryInfo
metoden och ersätt den hårdkodade frågesökvägen med settings.queryPath
.
var settings = JSON.parse(widgetSettings.customSettings.data);
if (!settings || !settings.queryPath) {
var $container = $('#query-info-container');
$container.empty();
$container.text("Sorry nothing to show, please configure a query path.");
return WidgetHelpers.WidgetStatusHelper.Success();
}
Nu är widgeten redo att återges med de konfigurerade inställningarna.
load
Både egenskaperna och reload
har en liknande funktion. Detta gäller för de flesta enkla widgetar.
För komplexa widgetar skulle det finnas vissa åtgärder som du skulle vilja köra bara en gång oavsett hur många gånger konfigurationen ändras.
Eller så kan det finnas vissa tunga åtgärder som inte behöver köras mer än en gång. Sådana åtgärder skulle vara en del av funktionen som motsvarar load
egenskapen och inte egenskapen reload
.
Steg 5: Uppdatera tilläggsmanifest
Öppna filen om du vss-extension.json
vill inkludera två nya poster i matrisen i egenskapen contributions
. En för widgeten HelloWorldWidget3
och den andra för dess konfiguration.
Du behöver ännu en förhandsgranskningsbild för den tredje widgeten. Namnge detta preview3.png
och placera det i img
mappen.
Uppdatera matrisen files
i egenskapen så att den innehåller de två nya HTML-filer som vi lade till i det här exemplet.
{
...
"contributions": [
... ,
{
"id": "HelloWorldWidget3",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog",
"fabrikam.azuredevops-extensions-myExtensions.HelloWorldWidget.Configuration"
],
"properties": {
"name": "Hello World Widget 3 (with config)",
"description": "My third widget",
"previewImageUrl": "img/preview3.png",
"uri": "hello-world3.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
},
{
"id": "HelloWorldWidget.Configuration",
"type": "ms.vss-dashboards-web.widget-configuration",
"targets": [ "ms.vss-dashboards-web.widget-configuration" ],
"properties": {
"name": "HelloWorldWidget Configuration",
"description": "Configures HelloWorldWidget",
"uri": "configuration.html"
}
}
],
"files": [
{
"path": "hello-world.html", "addressable": true
},
{
"path": "hello-world2.html", "addressable": true
},
{
"path": "hello-world3.html", "addressable": true
},
{
"path": "configuration.html", "addressable": true
},
{
"path": "sdk/scripts", "addressable": true
},
{
"path": "img", "addressable": true
}
],
...
}
Bidraget för widgetkonfigurationen följer en något annorlunda modell än själva widgeten. En bidragspost för widgetkonfiguration har:
- ID :t för att identifiera ditt bidrag. ID:t ska vara unikt i ett tillägg.
- Typ av bidrag. För alla widgetkonfigurationer bör det vara
ms.vss-dashboards-web.widget-configuration
- Matrisen med mål som bidraget bidrar till. För alla widgetkonfigurationer har den en enda post:
ms.vss-dashboards-web.widget-configuration
. - Egenskaperna som innehåller en uppsättning egenskaper som innehåller namn, beskrivning och URI för HTML-filen som används för konfiguration.
För att stödja konfigurationen måste widgetbidraget också ändras. Matrisen med mål för widgeten måste uppdateras för att inkludera ID:t för konfigurationen i formatet>publisher
< .><id for the extension
.id for the configuration contribution
<> som i det här fallet är .fabrikam.vsts-extensions-myExtensions.HelloWorldWidget.Configuration
Varning
Om bidragsposten för din konfigurerbara widget inte riktar sig mot konfigurationen med rätt utgivare och tilläggsnamn enligt beskrivningen ovan visas inte knappen konfigurera för widgeten.
I slutet av den här delen ska manifestfilen innehålla tre widgetar och en konfiguration. Du kan hämta det fullständiga manifestet från exemplet här.
Steg 6: Paketera, publicera och dela
Om tillägget inte har publicerats kan du läsa det här avsnittet. Om du redan har publicerat tillägget kan du packa om tillägget och uppdatera det direkt till Marketplace.
Steg 7: Lägg till widget från katalogen
Gå nu till din teaminstrumentpanel på https://dev.azure.com/{Your_Organization}/{Your_Project}. Om den här sidan redan är öppen uppdaterar du den. Hovra på Redigera och välj Lägg till. Den här åtgärden bör öppna widgetkatalogen där du hittar widgeten som du har installerat. Om du vill lägga till widgeten på instrumentpanelen väljer du widgeten och väljer Lägg till.
Ett meddelande som liknar följande ber dig att konfigurera widgeten.
Det finns två sätt att konfigurera widgetar. En är att hovra på widgeten, välja ellipsen som visas i det övre högra hörnet och sedan välja Konfigurera. Det andra är att välja knappen Redigera längst ned till höger på instrumentpanelen och sedan välja knappen Konfigurera som visas i det övre högra hörnet av widgeten. Antingen öppnas konfigurationsupplevelsen till höger och en förhandsgranskning av widgeten i mitten. Gå vidare och välj en fråga i listrutan. Live-förhandsgranskningen visar de uppdaterade resultaten. Välj Spara och widgeten visar de uppdaterade resultaten.
Steg 8: Konfigurera mer (valfritt)
Du kan lägga till så många HTML-formulärelement som du behöver i configuration.html
för mer konfiguration.
Det finns två konfigurerbara funktioner som är tillgängliga out-of-the-box: Widgetnamn och widgetstorlek.
Som standard lagras det namn som du anger för widgeten i tilläggsmanifestet som widgetnamn för varje instans av widgeten som någonsin läggs till på en instrumentpanel.
Du kan tillåta användare att konfigurera, så att de kan lägga till valfritt namn som de vill i sin instans av widgeten.
Om du vill tillåta en sådan konfiguration lägger du till isNameConfigurable:true
i avsnittet egenskaper för widgeten i tilläggsmanifestet.
Om du anger mer än en post för widgeten i matrisen supportedSizes
i tilläggsmanifestet kan användarna även konfigurera widgetens storlek.
Tilläggsmanifestet för det tredje exemplet i den här guiden skulle se ut som i följande exempel om vi aktiverar widgetens namn och storlekskonfiguration:
{
...
"contributions": [
... ,
{
"id": "HelloWorldWidget3",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog",
"fabrikam.azuredevops-extensions-myExtensions.HelloWorldWidget.Configuration"
],
"properties": {
"name": "Hello World Widget 3 (with config)",
"description": "My third widget",
"previewImageUrl": "img/preview3.png",
"uri": "hello-world3.html",
"isNameConfigurable": true,
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
},
{
"rowSpan": 2,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
},
...
]
}
Med föregående ändring packar du om och uppdaterar tillägget. Uppdatera instrumentpanelen som har den här widgeten (Hello World Widget 3 (med konfiguration)). Öppna konfigurationsläget för widgeten. Nu bör du kunna se alternativet att ändra widgetens namn och storlek.
Välj en annan storlek i listrutan. Du ser att liveförhandsgranskningen ändras. Spara ändringen och widgeten på instrumentpanelen ändras också.
Om du ändrar namnet på widgeten resulterar det inte i någon synlig ändring i widgeten eftersom våra exempelwidgetar inte visar widgetnamnet någonstans. Låt oss ändra exempelkoden för att visa widgetnamnet i stället för den hårdkodade texten "Hello World".
Det gör du genom att ersätta den hårdkodade texten "Hello World" med widgetSettings.name
på raden där vi anger elementets h2
text.
Den här åtgärden säkerställer att widgetnamnet visas varje gång widgeten läses in vid siduppdatering.
Eftersom vi vill att live-förhandsversionen ska uppdateras varje gång konfigurationen ändras bör vi även lägga till samma kod i den reload
del av koden.
Den slutliga retursatsen i hello-world3.html
är följande:
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text(widgetSettings.name);
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text(widgetSettings.name);
return getQueryInfo(widgetSettings);
}
}
Packa om och uppdatera tillägget igen. Uppdatera instrumentpanelen som har den här widgeten.
Alla ändringar av widgetens namn, i konfigurationsläget, uppdaterar widgettiteln nu.