Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022 | Azure DevOps Server 2020
Widgetar implementeras som bidrag i tilläggsramverket. Ett enda tillägg kan innehålla flera widgetbidrag. Den här artikeln visar hur du skapar ett tillägg som innehåller en eller flera widgetar.
Dricks
Kolla in vår senaste dokumentation om utveckling av tillägg med Azure DevOps Extension SDK.
Dricks
Om du startar ett nytt Azure DevOps-tillägg kan du prova dessa underhållsexempelsamlingar först – de fungerar med aktuella produktversioner och täcker moderna scenarier (till exempel att lägga till flikar på sidor med pull-begäranden).
- Azure DevOps-tilläggsexempel (GitHub) – ett kompakt startexempel som visar vanliga tilläggsmönster: https://github.com/microsoft/azure-devops-extension-sample
- Azure DevOps-tilläggsexempel (guide för äldre samlingar och bidrag) – installera för att inspektera UI-mål eller visa källan: https://marketplace.visualstudio.com/items/ms-samples.samples-contributions-guide och https://github.com/Microsoft/vso-extension-samples/tree/master/contributions-guide
- Microsoft Learn-exempel (bläddra bland Azure DevOps-exempel) – kuraterade, up-to-date-exempel i Microsoft-dokument: /samples/browse/?terms=azure%20devops%20extension
Installera det i en personlig organisation eller testorganisation om ett exempel inte fungerar i din organisation och jämför mål-ID för tilläggsmanifestet och API-versioner med de aktuella dokumenten. För referens och API:er, se:
Förutsättningar
| Krav | Beskrivning |
|---|---|
| Programmeringskunskaper | Kunskaper om JavaScript, HTML och CSS för widgetutveckling |
| Azure DevOps-organisation | Skapa en organisation |
| Textredigerare | Vi använder Visual Studio Code för självstudier |
| Node.js | Senaste versionen av Node.js |
| Plattformsoberoende CLI |
tfx-cli för att pakettera tillägg Installera med: npm i -g tfx-cli |
| Projektkatalog | Hemkatalog med den här strukturen när du har slutfört självstudien:|--- README.md|--- sdk |--- node_modules |--- scripts |--- VSS.SDK.min.js|--- img |--- logo.png|--- scripts|--- hello-world.html // html page for your widget|--- vss-extension.json // extension manifest |
Översikt över självstudier
I den här självstudien lär du dig utveckling av widgetar genom tre progressiva exempel:
| Del | Fokus | Det här lär du dig |
|---|---|---|
| Del 1: Hello World | Grundläggande skapande av widget | Skapa en widget som visar text |
| Del 2: REST API-integrering | Azure DevOps API-anrop | Lägga till REST API-funktioner för att hämta och visa data |
| Del 3: Widgetkonfiguration | Användaranpassning | Implementera konfigurationsalternativ för widgeten |
Dricks
Om du föredrar att gå direkt till fungerande exempel visar de inkluderade exemplen (se föregående anteckning) en uppsättning widgetar som du kan paketera och publicera.
Innan du börjar kan du läsa de grundläggande widgetformaten och den strukturella vägledning som vi tillhandahåller.
Del 1: Hello World
Skapa en grundläggande widget som visar "Hello World" med JavaScript. Den här grunden visar de grundläggande begreppen för widgetutveckling.
Steg 1: Installera klient-SDK
VSS SDK gör att widgeten kan kommunicera med Azure DevOps. Installera den med npm:
npm install vss-web-extension-sdk
VSS.SDK.min.js Kopiera filen från vss-web-extension-sdk/lib till mappenhome/sdk/scripts.
Mer SDK-dokumentation finns på GitHub-sidan för Klient-SDK.
Steg 2: Skapa HTML-strukturen
Skapa hello-world.html i projektkatalogen. Den här filen innehåller widgetens layout och referenser till nödvändiga skript.
<!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>
Widgetar körs i iframes, så de flesta HTML-huvudelement utom <script> och <link> ignoreras av ramverket.
Steg 3: Lägg till JavaScript-widget
Om du vill implementera widgetfunktionen lägger du till det här skriptet i <head> avsnittet i HTML-filen:
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/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>
Viktiga JavaScript-komponenter
| Funktion | Avsikt |
|---|---|
VSS.init() |
Initierar kommunikationen mellan widgeten och Azure DevOps |
VSS.require() |
Läser in nödvändiga SDK-bibliotek och widgethjälpare |
VSS.register() |
Registrerar widgeten med en unik identifierare |
WidgetHelpers.IncludeWidgetStyles() |
Tillämpar standardformatering för Azure DevOps |
VSS.notifyLoadSucceeded() |
Meddelar ramverket att inläsningen har slutförts |
Viktigt!
Widgetnamnet i VSS.register() måste matcha id i tilläggsmanifestet (steg 5).
Steg 4: Lägg till tilläggsbilder
Skapa de avbildningar som krävs för tillägget:
-
Tilläggslogotyp: bild med 98 x 98 bildpunkter med namnet
logo.pngiimgmappen -
Widgetkatalogikon: bild med 98 x 98 bildpunkter med namnet
CatalogIcon.pngiimgmappen -
Förhandsgranskning av widget: bild med 330 x 160 bildpunkter med namnet
preview.pngiimgmappen
Dessa bilder visas i Marketplace- och widgetkatalogen när användarna bläddrar bland tillgängliga tillägg.
Steg 5: Skapa tilläggsmanifestet
Skapa vss-extension.json i projektets rotkatalog. Den här filen definierar ditt tilläggs metadata och bidrag:
{
"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
}
]
}
Viktigt!
Ersätt "publisher": "fabrikam" med ditt faktiska utgivarnamn. Lär dig hur du skapar en utgivare.
Viktiga manifestegenskaper
| Sektion | Avsikt |
|---|---|
| Grundläggande information | Tilläggsnamn, version, beskrivning och utgivare |
| ikoner | Sökvägar till tilläggets visuella tillgångar |
| Bidrag | Widgetdefinitioner inklusive ID, typ och egenskaper |
| Filer | Alla filer som ska inkluderas i tilläggspaketet |
Fullständig manifestdokumentation finns i Tilläggsmanifestreferens.
Steg 6: Paketera och publicera tillägget
Paketera tillägget och publicera det på Visual Studio Marketplace.
Installera förpackningsverktyget
npm i -g tfx-cli
Skapa ditt tilläggspaket
Kör kommandot från din projektkatalog:
tfx extension create --manifest-globs vss-extension.json
Den här åtgärden skapar en .vsix fil som innehåller ditt paketerade tillägg.
Konfigurera en utgivare
- Gå till Visual Studio Marketplace-publiceringsportalen.
- Logga in och skapa en utgivare om du inte har någon.
- Välj en unik utgivaridentifierare (används i manifestfilen).
- Uppdatera ditt
vss-extension.jsonför att använda ditt utgivarnamn i stället för "fabrikam".
Ladda upp tillägget
- I publiceringsportalen väljer du Ladda upp nytt tillägg.
- Välj din
.vsixfil och ladda upp den. - Dela tillägget med din Azure DevOps-organisation.
Du kan också använda kommandoraden:
tfx extension publish --manifest-globs vss-extension.json --share-with yourOrganization
Dricks
Använd --rev-version för att automatiskt öka versionsnumret när du uppdaterar ett befintligt tillägg.
Steg 7: Installera och testa widgeten
Om du vill testa lägger du till widgeten på en instrumentpanel:
- Gå till ditt Azure DevOps-projekt:
https://dev.azure.com/{Your_Organization}/{Your_Project}. - Gå till Översikt>Instrumentpaneler.
- Välj Lägg till en widget.
- Leta upp widgeten i katalogen och välj Lägg till.
Widgeten "Hello World" visas på instrumentpanelen och visar den text som du har konfigurerat.
Nästa steg: Fortsätt till del 2 för att lära dig hur du integrerar Rest-API:er för Azure DevOps i din widget.
Del 2: Hello World med Azure DevOps REST API
Utöka widgeten så att den interagerar med Azure DevOps-data med hjälp av REST-API:er. Det här exemplet visar hur du hämtar frågeinformation och visar den dynamiskt i widgeten.
I den här delen använder du REST-API:et för arbetsobjektspårning för att hämta information om en befintlig fråga och visa frågeinformationen under texten "Hello World".
Steg 1: Skapa den förbättrade HTML-filen
Skapa en ny widgetfil som bygger på föregående exempel. Kopiera hello-world.html och byt namn på den till hello-world2.html. Projektstrukturen innehåller nu:
|--- README.md
|--- node_modules
|--- sdk/
|--- scripts/
|--- VSS.SDK.min.js
|--- img/
|--- logo.png
|--- scripts/
|--- hello-world.html // Part 1 widget
|--- hello-world2.html // Part 2 widget (new)
|--- vss-extension.json // Extension manifest
Uppdatera HTML-widgetens struktur
Gör dessa ändringar i hello-world2.html:
-
Lägg till en container för frågedata: Inkludera ett nytt
<div>element för att visa frågeinformation. -
Uppdatera widgetidentifieraren: Ändra widgetnamnet från
HelloWorldWidgettillHelloWorldWidget2för unik identifiering.
<!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"], 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: Konfigurera API-åtkomstbehörigheter
Innan du gör REST API-anrop konfigurerar du de behörigheter som krävs i tilläggsmanifestet.
Lägg till arbetsomfånget
Omfånget vso.work ger skrivskyddad åtkomst till arbetsobjekt och frågor. Lägg till det här omfånget i vss-extension.json:
{
"scopes": [
"vso.work"
]
}
Exempel på fullständigt manifest
För ett fullständigt manifest med andra egenskaper kan du strukturera det så här:
{
"name": "example-widget",
"publisher": "example-publisher",
"version": "1.0.0",
"scopes": [
"vso.work"
]
}
Viktigt!
Omfångsbegränsningar: Det går inte att lägga till eller ändra omfång efter publicering. Om du redan har publicerat tillägget måste du ta bort det från Marketplace först. Gå till Visual Studio Marketplace-publiceringsportalen, leta reda på tillägget och välj Ta bort.
Steg 3 i API-processen: Implementera REST API-integration
Azure DevOps tillhandahåller JavaScript REST-klientbibliotek via SDK:t. De här biblioteken omsluter AJAX-anrop och mappar API-svar till användbara objekt.
Uppdatera javascript-widgeten
Ersätt anropet VSS.require i din hello-world2.html för att inkludera REST-klienten för arbetsobjektspårning:
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"],
function (WidgetHelpers, WorkItemTrackingRestClient) {
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 WorkItemTrackingRestClient.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Process query data (implemented in Step 4)
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();
});
Viktig implementeringsinformation
| Komponent | Avsikt |
|---|---|
WorkItemTrackingRestClient.getClient() |
Hämtar en instans av REST-klienten för arbetsobjektspårning |
getQuery() |
Hämtar frågeinformation omsluten i ett löfte |
WidgetStatusHelper.Failure() |
Ger konsekvent felhantering vid widgetfel |
projectId |
Aktuell projektkontext som krävs för API-anrop |
Dricks
Anpassade frågesökvägar: Om du inte har en "Feedback"-fråga i "Delade frågor" ersätter "Shared Queries/Feedback" du med sökvägen till alla frågor som finns i projektet.
Steg 4: Visa API-svarsdata
Rendera frågeinformationen i widgeten genom att bearbeta REST API-svaret.
Lägga till frågedataåtergivning
Ersätt kommentaren // Process query data med den här implementeringen:
// 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);
Metoden getQuery() returnerar ett Contracts.QueryHierarchyItem objekt med egenskaper för frågemetadata. I det här exemplet visas tre viktiga informationsdelar under texten "Hello World".
Fullständigt arbetsexempel
Den slutliga hello-world2.html filen bör se ut så här:
<!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, WorkItemTrackingRestClient) {
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 WorkItemTrackingRestClient.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äggsmanifestet
Om du vill göra den tillgänglig i widgetkatalogen lägger du till din nya widget i tilläggsmanifestet.
Lägg till det andra widgetbidraget
Uppdatera vss-extension.json för att inkludera din REST API-aktiverade widget. Lägg till det här bidraget i matrisen contributions :
{
"contributions": [
// ...existing HelloWorldWidget contribution...,
{
"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"
]
}
Dricks
Förhandsgranskningsbild: Skapa en preview2.png bild (330 x 160 bildpunkter) och placera den img i mappen för att visa användarna hur widgeten ser ut i katalogen.
Steg 6: Paketera, publicera och dela
Paketera, publicera och dela tillägget. Om du redan har publicerat tillägget kan du paketera om och uppdatera det direkt på Marketplace.
Steg 7: Testa rest-API-widgeten
Om du vill visa REST API-integreringen i praktiken lägger du till den nya widgeten på instrumentpanelen:
- Gå till ditt Azure DevOps-projekt:
https://dev.azure.com/{Your_Organization}/{Your_Project}. - Välj Översikt>Instrumentpaneler.
- Välj Lägg till en widget.
- Leta upp "Hello World Widget 2 (med API)" och välj Lägg till.
Den förbättrade widgeten visar både texttexten "Hello World" och livefrågeinformationen från ditt Azure DevOps-projekt.
Nästa steg: Fortsätt till del 3 för att lägga till konfigurationsalternativ som låter användarna anpassa vilken fråga som ska visas.
Del 3: Konfigurera Hello World
Bygg vidare på del 2 genom att lägga till användarkonfigurationsmöjligheter i widgeten. I stället för att hårdkoda frågesökvägen skapar du ett konfigurationsgränssnitt som låter användarna välja vilken fråga som ska visas, med live-förhandsgranskningsfunktioner.
Den här delen visar hur du skapar konfigurerbara widgetar som användarna kan anpassa efter sina specifika behov samtidigt som de ger feedback i realtid under konfigurationen.
Steg 1: Skapa konfigurationsfiler
Widgetkonfigurationer delar många likheter med själva widgetarna – båda använder samma SDK, HTML-struktur och JavaScript-mönster, men har olika syften inom tilläggsramverket.
Konfigurera projektstrukturen
Skapa två nya filer för att stödja widgetkonfiguration:
- Kopiera
hello-world2.htmloch byt namn på den tillhello-world3.html, din konfigurerbara widget. - Skapa en ny fil med namnet
configuration.html, som hanterar konfigurationsgränssnittet.
Projektstrukturen innehåller nu:
|--- README.md
|--- sdk/
|--- node_modules
|--- scripts/
|--- VSS.SDK.min.js
|--- img/
|--- logo.png
|--- scripts/
|--- configuration.html // New: Configuration interface
|--- hello-world.html // Part 1: Basic widget
|--- hello-world2.html // Part 2: REST API widget
|--- hello-world3.html // Part 3: Configurable widget (new)
|--- vss-extension.json // Extension manifest
Skapa konfigurationsgränssnittet
Lägg till den här HTML-strukturen i configuration.html, som skapar en listruteväljare för att välja frågor:
<!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: Implementera konfiguration av JavaScript
JavaScript-konfigurationen följer samma initieringsmönster som widgetar, men implementerar IWidgetConfiguration kontraktet i stället för det grundläggande IWidget kontraktet.
Lägga till konfigurationslogik
Infoga det här skriptet <head> i avsnittet configuration.html:
<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>
Information om konfigurationskontrakt
Kontraktet IWidgetConfiguration kräver följande nyckelfunktioner:
| Funktion | Avsikt | När det anropas |
|---|---|---|
load() |
Initiera konfigurationsgränssnittet med befintliga inställningar | När konfigurationsdialogrutan öppnas |
onSave() |
Serialisera användarindata och verifiera inställningar | När användaren väljer Spara |
Dricks
Dataserialisering: I det här exemplet används JSON för att serialisera inställningar. Widgeten kommer åt dessa inställningar via widgetSettings.customSettings.data och måste deserialisera dem i enlighet med detta.
Steg 3: Aktivera funktioner för liveförhandsgranskning
Med liveförhandsgranskning kan användarna se widgetändringar omedelbart när de ändrar konfigurationsinställningarna, vilket ger omedelbar feedback innan de sparar.
Implementera ändringsmeddelanden
Om du vill aktivera liveförhandsgranskning lägger du till den här händelsehanteraren i load funktionen:
$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);
});
Fullständig konfigurationsfil
Din slutliga configuration.html bör se ut så här:
<!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>
Viktigt!
Aktivera knappen Spara: Ramverket kräver minst ett meddelande om konfigurationsändring för att aktivera knappen Spara . Händelsehanteraren för ändring ser till att den här åtgärden inträffar när användare väljer ett alternativ.
Steg 4: Gör widgeten konfigurerbar
Transformera widgeten från del 2 för att använda konfigurationsdata i stället för hårdkodade värden. Det här steget kräver att implementera kontraktet IConfigurableWidget.
Uppdatera widgetregistrering
I hello-world3.htmlgör du följande ändringar:
-
Uppdatera widget-ID: Ändra från
HelloWorldWidget2tillHelloWorldWidget3. -
Lägg till omladdningsfunktion: Implementera
IConfigurableWidget-kontraktet.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
return getQueryInfo(widgetSettings);
}
}
Hantera konfigurationsdata
getQueryInfo Uppdatera funktionen så att den använder konfigurationsinställningar i stället för hårdkodade frågesökvägar:
var settings = JSON.parse(widgetSettings.customSettings.data);
if (!settings || !settings.queryPath) {
var $container = $('#query-info-container');
$container.empty();
$container.text("Please configure a query path to display data.");
return WidgetHelpers.WidgetStatusHelper.Success();
}
Skillnader i widgetens livscykel
| Funktion | Avsikt | Användningsriktlinjer |
|---|---|---|
load() |
Inledande widgetåtergivning och engångskonfiguration | Tunga åtgärder, resursinitiering |
reload() |
Uppdatera widget med ny konfiguration | Lätta uppdateringar, datauppdatering |
Dricks
Prestandaoptimering: Använd load() för dyra åtgärder som bara behöver köras en gång och reload() för snabba uppdateringar när konfigurationen ändras.
(Valfritt) Lägg till en ljusruta för detaljerad information
Instrumentpanelswidgetar har begränsat utrymme, vilket gör det svårt att visa omfattande information. En lightbox ger en elegant lösning genom att visa detaljerade data i ett modalt överlägg utan att navigera bort från instrumentpanelen.
Varför ska du använda en lightbox i widgetar?
| Förmån | Beskrivning |
|---|---|
| Utrymmeseffektivitet | Håll widget kompakt samtidigt som du erbjuder detaljerade vyer |
| Användarupplevelse | Underhålla instrumentpanelskontexten samtidigt som mer information visas |
| Progressivt avslöjande | Visa sammanfattningsdata i widgeten, detaljer vid behov |
| dynamisk design | Anpassa till olika skärmstorlekar och widgetkonfigurationer |
Implementera klickbara element
Uppdatera frågedataåtergivningen så att den innehåller klickbara element som utlöser ljusrutan:
// Create a list with clickable query details
var $list = $('<ul class="query-summary">');
$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>"));
// Add a clickable element to open detailed view
var $detailsLink = $('<button class="details-link">View Details</button>');
$detailsLink.on('click', function() {
showQueryDetails(query);
});
// Append to the container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
$container.append($detailsLink);
Skapa lightbox-funktionen
Lägg till den här lightbox-implementeringen i javascript-widgeten:
function showQueryDetails(query) {
// Create lightbox overlay
var $overlay = $('<div class="lightbox-overlay">');
var $lightbox = $('<div class="lightbox-content">');
// Add close button
var $closeBtn = $('<button class="lightbox-close">×</button>');
$closeBtn.on('click', function() {
$overlay.remove();
});
// Create detailed content
var $content = $('<div class="query-details">');
$content.append($('<h3>').text(query.name || 'Query Details'));
$content.append($('<p>').html('<strong>ID:</strong> ' + query.id));
$content.append($('<p>').html('<strong>Path:</strong> ' + query.path));
$content.append($('<p>').html('<strong>Created:</strong> ' + (query.createdDate ? new Date(query.createdDate).toLocaleDateString() : 'Unknown')));
$content.append($('<p>').html('<strong>Modified:</strong> ' + (query.lastModifiedDate ? new Date(query.lastModifiedDate).toLocaleDateString() : 'Unknown')));
$content.append($('<p>').html('<strong>Created By:</strong> ' + (query.createdBy ? query.createdBy.displayName : 'Unknown')));
$content.append($('<p>').html('<strong>Modified By:</strong> ' + (query.lastModifiedBy ? query.lastModifiedBy.displayName : 'Unknown')));
if (query.queryType) {
$content.append($('<p>').html('<strong>Type:</strong> ' + query.queryType));
}
// Assemble lightbox
$lightbox.append($closeBtn);
$lightbox.append($content);
$overlay.append($lightbox);
// Add to document and show
$('body').append($overlay);
// Close on overlay click
$overlay.on('click', function(e) {
if (e.target === $overlay[0]) {
$overlay.remove();
}
});
// Close on Escape key
$(document).on('keydown.lightbox', function(e) {
if (e.keyCode === 27) { // Escape key
$overlay.remove();
$(document).off('keydown.lightbox');
}
});
}
Lägg till lightbox-stil
Inkludera CSS-stilar för lightboxen i HTML-avsnittet <head> :
<style>
.query-summary {
list-style: none;
padding: 0;
margin: 10px 0;
}
.query-summary li {
padding: 2px 0;
font-size: 12px;
}
.details-link {
background: #0078d4;
color: white;
border: none;
padding: 4px 8px;
font-size: 11px;
cursor: pointer;
border-radius: 2px;
margin-top: 8px;
}
.details-link:hover {
background: #106ebe;
}
.lightbox-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
}
.lightbox-content {
background: white;
border-radius: 4px;
padding: 20px;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
position: relative;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.lightbox-close {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
line-height: 1;
}
.lightbox-close:hover {
color: #000;
}
.query-details h3 {
margin-top: 0;
color: #323130;
}
.query-details p {
margin: 8px 0;
font-size: 14px;
line-height: 1.4;
}
</style>
Förbättrad widgetimplementering
Din kompletta förbättrade widget med lightbox-funktioner:
<!DOCTYPE html>
<html>
<head>
<script src="sdk/scripts/VSS.SDK.min.js"></script>
<style>
/* Lightbox styles from above */
.query-summary {
list-style: none;
padding: 0;
margin: 10px 0;
}
.query-summary li {
padding: 2px 0;
font-size: 12px;
}
.details-link {
background: #0078d4;
color: white;
border: none;
padding: 4px 8px;
font-size: 11px;
cursor: pointer;
border-radius: 2px;
margin-top: 8px;
}
.details-link:hover {
background: #106ebe;
}
.lightbox-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
}
.lightbox-content {
background: white;
border-radius: 4px;
padding: 20px;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
position: relative;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.lightbox-close {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
line-height: 1;
}
.lightbox-close:hover {
color: #000;
}
.query-details h3 {
margin-top: 0;
color: #323130;
}
.query-details p {
margin: 8px 0;
font-size: 14px;
line-height: 1.4;
}
</style>
<script type="text/javascript">
VSS.init({
explicitNotifyLoaded: true,
usePlatformStyles: true
});
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"],
function (WidgetHelpers, WorkItemTrackingRestClient) {
WidgetHelpers.IncludeWidgetStyles();
function showQueryDetails(query) {
// Lightbox implementation from above
}
VSS.register("HelloWorldWidget2", function () {
var projectId = VSS.getWebContext().project.id;
var getQueryInfo = function (widgetSettings) {
return WorkItemTrackingRestClient.getClient().getQuery(projectId, "Shared Queries/Feedback")
.then(function (query) {
// Enhanced display with lightbox trigger
var $list = $('<ul class="query-summary">');
$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>")));
var $detailsLink = $('<button class="details-link">View Details</button>');
$detailsLink.on('click', function() {
showQueryDetails(query);
});
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
$container.append($detailsLink);
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();
});
</script>
</head>
<body>
<div class="widget">
<h2 class="title"></h2>
<div id="query-info-container"></div>
</div>
</body>
</html>
Hjälpmedelsöverväganden: Se till att din ljusruta är tangentbordstillgänglig och innehåller rätt etiketter för skärmläsare. Testa med Azure DevOps inbyggda hjälpmedelsfunktioner.
Viktigt!
Prestanda: Lightbox-rutor bör läsas in snabbt. Överväg att endast ladda detaljerad data när lightboxen öppnas i stället för att hämta allt i förväg.
Steg 5: Konfigurera tilläggsmanifestet
Registrera både den konfigurerbara widgeten och dess konfigurationsgränssnitt i tilläggsmanifestet.
Lägg till widget- och konfigurationstillägg
Uppdatera vss-extension.json för att inkludera två nya bidrag:
{
"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
},
{
"rowSpan": 2,
"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
}
]
}
Krav för konfigurationsbidrag
| Egendom | Avsikt | Obligatoriskt värde |
|---|---|---|
type |
Identifierar bidrag som widgetkonfiguration | ms.vss-dashboards-web.widget-configuration |
targets |
Där konfigurationen visas | ms.vss-dashboards-web.widget-configuration |
uri |
Sökväg till HTML-konfigurationsfil | Din konfigurationsfilsökväg |
Riktmönster för widget
För konfigurerbara widgetar måste matrisen targets innehålla en referens till konfigurationen:
<publisher>.<extension-id>.<configuration-id>
Varning
Synlighet för konfigurationsknapp: Om widgeten inte är korrekt inriktad på sitt konfigurationsbidrag visas inte knappen Konfigurera . Kontrollera att utgivar- och tilläggsnamnen matchar manifestet exakt.
Steg 6: Paketera, publicera och dela
Distribuera ditt utökade tillägg med konfigurationsfunktioner.
Om det är din första publikation följer du Steg 6: Paketera, publicera och dela. För befintliga tillägg packar du om och uppdaterar direkt på Marketplace.
Steg 7: Testa den konfigurerbara widgeten
Upplev det fullständiga konfigurationsarbetsflödet genom att lägga till och konfigurera widgeten.
Lägg till widgeten på instrumentpanelen
- Gå till
https://dev.azure.com/{Your_Organization}/{Your_Project}. - Gå till Översikt>Instrumentpaneler.
- Välj Lägg till en widget.
- Leta upp "Hello World Widget 3 (med konfiguration)" och välj Lägg till.
En konfigurationsprompt visas eftersom widgeten kräver installation:
Konfigurera widgeten
Åtkomstkonfiguration via någon av metoderna:
- Widget-menyn: Hovra över widgeten, välj ellipsen (⋯) och sedan Konfigurera
- Redigeringsläge för instrumentpanelen: Välj Redigera på instrumentpanelen och sedan knappen konfigurera på widgeten
Konfigurationspanelen öppnas med en live-förhandsversion i mitten. Välj en fråga i listrutan för att se omedelbara uppdateringar och välj sedan Spara för att tillämpa ändringarna.
Steg 8: Lägg till avancerade konfigurationsalternativ
Utöka widgeten med fler inbyggda konfigurationsfunktioner som anpassade namn och storlekar.
Aktivera konfiguration av namn och storlek
Azure DevOps erbjuder två konfigurerbara funktioner direkt utanför boxen:
| Egenskap | Manifest egenskap | Avsikt |
|---|---|---|
| Anpassade namn | isNameConfigurable: true |
Användare kan åsidosätta standardwidgetnamnet |
| Flera storlekar | Flera supportedSizes poster |
Användare kan ändra storlek på widgetar |
Förbättrat manifestexempel
{
"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"]
}
}
]
}
Visa konfigurerade namn
Om du vill visa anpassade widgetnamn uppdaterar du widgeten så att den använder widgetSettings.name:
return {
load: function (widgetSettings) {
// Display configured name instead of hard-coded text
var $title = $('h2.title');
$title.text(widgetSettings.name);
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
// Update name during configuration changes
var $title = $('h2.title');
$title.text(widgetSettings.name);
return getQueryInfo(widgetSettings);
}
}
När du har uppdaterat tillägget kan du konfigurera både widgetens namn och storlek:
Packa om och uppdatera tillägget för att aktivera de här avancerade konfigurationsalternativen.
Grattis! Du har skapat en fullständig, konfigurerbar Azure DevOps-instrumentpanelswidget med funktioner för liveförhandsgranskning och alternativ för användaranpassning.