Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022
Widgety se implementují jako příspěvky v rámci rozšíření. Jedno rozšíření může obsahovat více příspěvků widgetů. Tento článek ukazuje, jak vytvořit rozšíření, které poskytuje jeden nebo více widgetů.
Návod
Projděte si nejnovější dokumentaci k vývoji rozšíření pomocí sady SDK rozšíření Azure DevOps.
Návod
Pokud spouštíte nové rozšíření Azure DevOps, vyzkoušejte nejdřív tyto spravované ukázkové kolekce – pracují s aktuálními buildy produktů a pokrývají moderní scénáře (například přidávání karet na stránkách žádostí o přijetí změn).
- Ukázka rozšíření Azure DevOps (GitHub) – kompaktní úvodní ukázka, která demonstruje běžné vzory rozšíření: https://github.com/microsoft/azure-devops-extension-sample
- Ukázky rozšíření Azure DevOps (průvodce ke starším kolekcím a návodům na kontribuce) – nainstalujte pro kontrolu cílů uživatelského rozhraní nebo pro zobrazení zdroje: https://marketplace.visualstudio.com/items/ms-samples.samples-contributions-guidehttps://github.com/Microsoft/vso-extension-samples/tree/master/contributions-guide
- Ukázky Microsoft Learn (příklady Azure DevOps) – kurátorované, aktuální ukázky v dokumentaci Microsoftu: /samples/browse/?terms=azure%20devops%20extension
Pokud ukázka ve vaší organizaci nefunguje, nainstalujte ji do osobní nebo testovací organizace a porovnejte cílové ID manifestu rozšíření a verze rozhraní API s aktuálními dokumenty. Referenční informace a rozhraní API najdete tady:
Požadavky
| Požadavek | Popis |
|---|---|
| Znalosti programování | Znalosti JavaScriptu, HTML a CSS pro vývoj widgetů |
| Organizace Azure DevOps | Vytvoření organizace |
| Textový editor | Visual Studio Code používáme pro kurzy |
| Node.js | Nejnovější verze Node.js |
| Multiplatformní CLI |
tfx-cli pro balení rozšíření Instalace pomocí: npm i -g tfx-cli |
| Adresář projektu | Domovský adresář s touto strukturou po dokončení kurzu:|--- 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 |
Přehled kurzů
V tomto kurzu se naučíte vývoj widgetů prostřednictvím tří progresivních příkladů:
| Část | Soustředění | Co se naučíte |
|---|---|---|
| Část 1: Hello World | Vytvoření základního widgetu | Vytvoření widgetu, který zobrazuje text |
| Část 2: Integrace rozhraní REST API | Volání rozhraní API Azure DevOps | Přidání funkcí rozhraní REST API pro načtení a zobrazení dat |
| Část 3: Konfigurace widgetu | Přizpůsobení uživatele | Implementace možností konfigurace pro widget |
Návod
Pokud chcete přejít přímo na pracovní příklady, zahrnuté ukázky (viz předchozí poznámka) ukazují sadu widgetů, které můžete zabalit a publikovat.
Než začnete, projděte si základní styly widgetů a strukturální pokyny, které poskytujeme.
Část 1: Hello World
Vytvořte základní widget, který zobrazí "Hello World" pomocí JavaScriptu. Tento základ ukazuje základní koncepty vývoje widgetů.
Krok 1: Instalace klientské sady SDK
Sada VSS SDK umožňuje vaší widgetu komunikovat s Azure DevOps. Nainstalujte ho pomocí npm:
npm install vss-web-extension-sdk
Zkopírujte soubor VSS.SDK.min.js z vss-web-extension-sdk/lib do své složky home/sdk/scripts.
Další dokumentaci k sadě SDK najdete na stránce GitHub klientské sady SDK.
Krok 2: Vytvoření struktury HTML
Vytvořte hello-world.html v adresáři projektu. Tento soubor poskytuje rozložení widgetu a odkazy na požadované skripty.
<!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>
Widgety běží v elementech iframe, takže většina prvků v hlavičce HTML s výjimkou <script> a <link> je ignorována frameworkem.
Krok 3: Přidání widgetu JavaScriptu
Pokud chcete implementovat funkci widgetu, přidejte tento skript do <head> části souboru HTML:
<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>
Klíčové komponenty JavaScriptu
| Funkce | Účel |
|---|---|
VSS.init() |
Inicializuje komunikaci mezi widgetem a Azure DevOps. |
VSS.require() |
Načítá požadované knihovny SDK a pomocné moduly widgetů |
VSS.register() |
Zaregistruje widget s jedinečným identifikátorem. |
WidgetHelpers.IncludeWidgetStyles() |
Použije výchozí styly Azure DevOps. |
VSS.notifyLoadSucceeded() |
Upozorní rámec, že se načítání úspěšně dokončilo. |
Důležité
Název VSS.register() widgetu se musí shodovat s manifestem id rozšíření (krok 5).
Krok 4: Přidání obrázků rozšíření
Vytvořte požadované image pro vaše rozšíření:
-
Logo rozšíření: 98x98 pixelový obrázek s názvem
logo.pngve složceimg -
Ikona katalogu widgetů: obrázek 98x98 pixelů pojmenovaný
CatalogIcon.pngveimgsložce -
Náhled widgetu: obrázek 330 × 160 pixelů pojmenovaný
preview.pngveimgsložce
Tyto obrázky se zobrazují v katalogu marketplace a widgetů, když uživatelé procházejí dostupná rozšíření.
Krok 5: Vytvoření manifestu rozšíření
Vytvořte vss-extension.json v kořenovém adresáři projektu. Tento soubor definuje metadata a příspěvky rozšíření:
{
"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
}
]
}
Důležité
Nahraďte "publisher": "fabrikam" skutečným názvem vydavatele. Zjistěte, jak vytvořit vydavatele.
Základní vlastnosti manifestu
| Oddíl | Účel |
|---|---|
| Základní informace | Název rozšíření, verze, popis a vydavatel |
| ikony | Cesty k vizuálním prvkům rozšíření |
| Příspěvky | Definice widgetů včetně ID, typu a vlastností |
| Soubory | Všechny soubory, které se mají zahrnout do balíčku rozšíření |
Kompletní dokumentaci k manifestu najdete v referenčních informacích k manifestu rozšíření.
Krok 6: Zabalení a publikování rozšíření
Zabalte rozšíření a publikujte ho na Visual Studio Marketplace.
Instalace nástroje pro balení
npm i -g tfx-cli
Vytvoření balíčku rozšíření
V adresáři projektu spusťte:
tfx extension create --manifest-globs vss-extension.json
Tato akce vytvoří .vsix soubor, který obsahuje zabalenou příponu.
Nastavení vydavatele
- Přejděte na portál publikování na Webu Visual Studio Marketplace.
- Pokud ho nemáte, přihlaste se a vytvořte vydavatele.
- Zvolte jedinečný identifikátor vydavatele (použitý v souboru manifestu).
- Aktualizujte
vss-extension.jsontak, aby používalo jméno vašeho vydavatele místo "fabrikam".
Nahrajte rozšíření
- Na portálu publikování vyberte Nahrát nové rozšíření.
- Zvolte soubor
.vsixa nahrajte ho. - Sdílejte rozšíření s vaší organizací Azure DevOps.
Případně použijte příkazový řádek:
tfx extension publish --manifest-globs vss-extension.json --share-with yourOrganization
Návod
Slouží --rev-version k automatickému zvýšení čísla verze při aktualizaci existujícího rozšíření.
Krok 7: Instalace a otestování widgetu
Pokud chcete widget otestovat, přidejte ho na řídicí panel:
- Přejděte do projektu Azure DevOps:
https://dev.azure.com/{Your_Organization}/{Your_Project}. - Přejděte na Přehled>Řídicí panely.
- Vyberte Přidejte pomůcku.
- Vyhledejte widget v katalogu a vyberte Přidat.
Na řídicím panelu se zobrazí widget "Hello World", který zobrazuje text, který jste nakonfigurovali.
Další krok: Pokračujte 2. částí a zjistěte, jak integrovat rozhraní REST API Azure DevOps do widgetu.
Část 2: Hello World s využitím azure DevOps REST API
Rozšíření widgetu pro interakci s daty Azure DevOps pomocí rozhraní REST API Tento příklad ukazuje, jak načíst informace o dotazu a dynamicky je zobrazit ve widgetu.
V této části použijte rozhraní REST API pro sledování pracovních položek k načtení informací o existujícím dotazu a zobrazení podrobností dotazu pod textem Hello World.
Krok 1: Vytvoření rozšířeného souboru HTML
Vytvořte nový soubor widgetu, který vychází z předchozího příkladu. Zkopírujte a přejmenujte hello-world.html ho na hello-world2.html. Struktura projektu teď zahrnuje:
|--- 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
Aktualizace struktury HTML widgetu
Proveďte tyto změny na hello-world2.html:
-
Přidání kontejneru pro data dotazu: Přidejte nový
<div>prvek pro zobrazení informací o dotazu. -
Aktualizujte identifikátor widgetu: Změňte název widgetu z
HelloWorldWidgetnaHelloWorldWidget2pro jedinečnou identifikaci.
<!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>
Krok 2: Konfigurace přístupových oprávnění rozhraní API
Před voláním rozhraní REST API nakonfigurujte požadovaná oprávnění v manifestu rozšíření.
Přidání oboru práce
Rozsah vso.work uděluje přístup k pracovním položkám a dotazům pouze pro čtení. Přidejte tento obor do svého vss-extension.json:
{
"scopes": [
"vso.work"
]
}
Kompletní příklad manifestu
Úplný manifest s dalšími vlastnostmi strukturujte takto:
{
"name": "example-widget",
"publisher": "example-publisher",
"version": "1.0.0",
"scopes": [
"vso.work"
]
}
Důležité
Omezení oboru: Přidání nebo změna oborů po publikování se nepodporuje. Pokud jste rozšíření už publikovali, musíte ho nejprve odebrat z Marketplace. Přejděte na portál publikování na Webu Visual Studio Marketplace, vyhledejte rozšíření a vyberte Odebrat.
Krok 3: Implementace integrace rozhraní REST API
Azure DevOps poskytuje klientské knihovny REST jazyka JavaScript prostřednictvím sady SDK. Tyto knihovny zabalí volání AJAX a mapují odpovědi rozhraní API na použitelné objekty.
Aktualizace widgetu v JavaScriptu
Nahraďte v VSS.require volání hello-world2.html, abyste zahrnuli REST klienta pro sledování pracovních položek.
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();
});
Klíčové podrobnosti implementace
| Součást | Účel |
|---|---|
WorkItemTrackingRestClient.getClient() |
Získá instanci klienta rozhraní REST pro sledování položek práce. |
getQuery() |
Načte informace o dotazu zabalené do příslibu. |
WidgetStatusHelper.Failure() |
Poskytuje konzistentní zpracování chyb při selhání widgetu. |
projectId |
Aktuální kontext projektu vyžadovaný pro volání rozhraní API |
Návod
Vlastní cesty dotazů: Pokud nemáte v části Sdílené dotazy dotaz Feedback, nahraďte "Shared Queries/Feedback" cestu k jakémukoli dotazu, který v projektu existuje.
Krok 4: Zobrazení dat odpovědí rozhraní API
Vykreslete informace z dotazu ve vašem widgetu zpracováním odpovědi z REST API.
Přidání vykreslování dat dotazů
// Process query data Nahraďte komentář touto implementací:
// 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);
Metoda getQuery() vrátí Contracts.QueryHierarchyItem objekt s vlastnostmi pro metadata dotazu. Tento příklad zobrazuje tři klíčové informace pod textem "Hello World".
Příklad dokončení práce
Konečný hello-world2.html soubor by měl vypadat takto:
<!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>
Krok 5: Aktualizace manifestu rozšíření
Pokud ho chcete zpřístupnit v katalogu widgetů, přidejte nový widget do manifestu rozšíření.
Přidání druhého příspěvku widgetu
Aktualizujte vss-extension.json tak, aby zahrnoval widget s podporou rozhraní REST API. Přidejte tento příspěvek do contributions pole:
{
"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"
]
}
Návod
Obrázek náhledu: Vytvořte preview2.png obrázek (330 × 160 pixelů) a umístěte ho do img složky, abyste uživatelům ukázali, jak váš widget vypadá v katalogu.
Krok 6: Balení, publikování a sdílení
Zabalte, publikujte a sdílejte své rozšíření. Pokud jste rozšíření už publikovali, můžete ho znovu zabalit a aktualizovat přímo na Marketplace.
Krok 7: Testování widgetu rozhraní REST API
Pokud chcete zobrazit integraci rozhraní REST API v akci, přidejte do řídicího panelu nový widget:
- Přejděte do projektu Azure DevOps:
https://dev.azure.com/{Your_Organization}/{Your_Project}. - Vyberte Přehled>Řídicí panely.
- Vyberte Přidejte pomůcku.
- Najděte "Hello World Widget 2 (s rozhraním API)" a vyberte Přidat.
Ve vylepšeném widgetu se zobrazí text "Hello World" i informace o živém dotazu z projektu Azure DevOps.
Další kroky: Pokračujte na část 3 a přidejte možnosti konfigurace, které uživatelům umožňují přizpůsobit, který dotaz se má zobrazit.
Část 3: Konfigurace Hello World
Navázat na část 2 přidáním možností konfigurace uživatele do widgetu. Místo pevného kódování cesty dotazu vytvořte konfigurační rozhraní, které uživatelům umožňuje vybrat dotaz, který se má zobrazit, s funkcemi živého náhledu.
Tato část ukazuje, jak vytvořit konfigurovatelné widgety, které si uživatelé můžou přizpůsobit podle svých konkrétních potřeb a současně poskytnout zpětnou vazbu v reálném čase během konfigurace.
Krok 1: Vytvoření konfiguračních souborů
Konfigurace widgetů sdílejí mnoho podobností s vlastními widgety – používají stejnou sadu SDK, strukturu HTML i vzory JavaScriptu, ale v rámci architektury rozšíření slouží různým účelům.
Nastavení struktury projektu
Pokud chcete podporovat konfiguraci widgetu, vytvořte dva nové soubory:
- Zkopírujte ho a přejmenujte
hello-world2.htmlnahello-world3.htmlkonfigurovatelný widget. - Vytvořte nový soubor s názvem
configuration.html, který zpracovává konfigurační rozhraní.
Struktura projektu teď zahrnuje:
|--- 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
Vytvoření konfiguračního rozhraní
Přidejte tuto strukturu HTML do configuration.html, která vytvoří selektor rozevíracího seznamu pro výběr dotazů:
<!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>
Krok 2: Implementace konfigurace JavaScriptu
Konfigurace JavaScriptu se řídí stejným vzorem inicializace jako widgety, ale implementuje IWidgetConfiguration kontrakt místo základního IWidget kontraktu.
Přidejte logiku konfigurace
Vložte tento skript do <head> části 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>
Podrobnosti o konfiguraci smlouvy
Kontrakt IWidgetConfiguration vyžaduje tyto klíčové funkce:
| Funkce | Účel | Při zavolání |
|---|---|---|
load() |
Inicializujte konfigurační uživatelské rozhraní pomocí existujících nastavení | Po otevření dialogového okna konfigurace |
onSave() |
Serializace uživatelského vstupu a ověření nastavení | Když uživatel vybere Možnost Uložit |
Návod
Serializace dat: V tomto příkladu se k serializaci nastavení používá JSON. Widget k těmto nastavením přistupuje prostřednictvím widgetSettings.customSettings.data a musí je odpovídajícím způsobem deserializovat.
Krok 3: Povolení funkce živého náhledu
Dynamický náhled umožňuje uživatelům zobrazit změny widgetu okamžitě při úpravě nastavení konfigurace a poskytnout okamžitou zpětnou vazbu před uložením.
Implementace oznámení o změnách
Pokud chcete povolit dynamický náhled, přidejte tuto obslužnou rutinu události do funkce 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);
});
Dokončení konfiguračního souboru
Váš configuration.html by měl vypadat takto:
<!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>
Důležité
Povolit tlačítko Uložit: Rozhraní vyžaduje alespoň jedno oznámení o změně konfigurace, aby bylo možné povolit tlačítko Uložit . Obslužná rutina události změny zajistí, že k této akci dojde, když uživatelé vyberou možnost.
Krok 4: Nastavení konfigurovatelného widgetu
Transformujte widget z části 2 tak, aby místo pevně zakódovaných hodnot používal konfigurační data. Tento krok vyžaduje implementaci kontraktu IConfigurableWidget .
Aktualizace registrace widgetu
V hello-world3.htmlaplikaci proveďte tyto změny:
-
Aktualizovat ID widgetu: Změna z
HelloWorldWidget2naHelloWorldWidget3. -
Přidání funkce pro opětovné načtení: Implementujte
IConfigurableWidgetkontrakt.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
return getQueryInfo(widgetSettings);
}
}
Zpracování konfiguračních dat
Aktualizujte funkci tak getQueryInfo , aby místo pevně zakódovaných cest dotazů používala nastavení konfigurace:
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();
}
Rozdíly životního cyklu widgetu
| Funkce | Účel | Pokyny k používání |
|---|---|---|
load() |
Počáteční vykreslování widgetů a jednorázové nastavení | Náročné operace, inicializace prostředků |
reload() |
Aktualizace widgetu s novou konfigurací | Zjednodušené aktualizace, aktualizace dat |
Návod
Optimalizace výkonu: Používejte load() pro nákladné operace, které stačí spustit jen jednou, a reload() rychlé aktualizace při změnách konfigurace.
(Volitelné) Přidání lightboxu pro podrobné informace
Widgety řídicího panelu mají omezený prostor, což ztěžuje zobrazení komplexních informací. Lightbox poskytuje elegantní řešení zobrazením podrobných dat v modální překryvné oblasti, aniž byste museli přecházet z řídicího panelu.
Proč používat lightbox ve widgetech?
| Prospěch | Popis |
|---|---|
| Prostorová efektivita | Zachování kompaktního widgetu při nabízení podrobných zobrazení |
| Uživatelské prostředí | Zachování kontextu řídicího panelu při zobrazení dalších informací |
| Postupné odhalení | Zobrazení souhrnných dat ve widgetu, podrobnosti na vyžádání |
| Responzivní návrh | Přizpůsobení různých velikostí obrazovek a konfigurací widgetů |
Implementace klikatelných elementů
Aktualizujte vykreslování dat dotazů tak, aby zahrnovalo kliknutelné prvky, které aktivují lightbox:
// 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);
Vytvoření funkce lightboxu
Přidejte tuto implementaci lightboxu do JavaScriptu widgetu:
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');
}
});
}
Přidání stylu lightboxu
Do oddílu HTML <head> widgetu zahrňte styly CSS pro lightbox:
<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>
Vylepšená implementace widgetu
Kompletní vylepšený widget s funkcemi lightboxu:
<!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>
Aspekty přístupnosti: Ujistěte se, že lightbox je přístupný z klávesnice a obsahuje správné popisky pro čtečky obrazovky. Testování pomocí integrovaných funkcí přístupnosti v Azure DevOps
Důležité
Výkon: Lightboxes by se měly načíst rychle. Zvažte načítání podrobných dat metodou lazy-loading pouze tehdy, když se lightbox otevře, místo načítání všeho předem.
Krok 5: Konfigurace manifestu rozšíření
Zaregistrujte v manifestu rozšíření konfigurovatelný widget i jeho konfigurační rozhraní.
Přidání widgetu a příspěvků ke konfiguraci
Aktualizace vss-extension.json pro zahrnutí dvou nových příspěvků:
{
"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
}
]
}
Požadavky na přispění k nastavení konfigurace
| Vlastnost | Účel | Požadovaná hodnota |
|---|---|---|
type |
Identifikuje příspěvek jako konfiguraci widgetu. | ms.vss-dashboards-web.widget-configuration |
targets |
Kde se zobrazí konfigurace | ms.vss-dashboards-web.widget-configuration |
uri |
Cesta ke konfiguračnímu souboru HTML | Cesta ke konfiguračnímu souboru |
Model cílení widgetů
Pro konfigurovatelné widgety targets musí pole obsahovat odkaz na konfiguraci:
<publisher>.<extension-id>.<configuration-id>
Upozorňující
Viditelnost tlačítka konfigurace: Pokud widget nemá správný cíl na svůj příspěvek konfigurace, tlačítko Konfigurovat se nezobrazí. Ověřte, že názvy vydavatelů a přípon přesně odpovídají vašemu manifestu.
Krok 6: Balení, publikování a sdílení
Nasaďte rozšířené rozšíření s možnostmi konfigurace.
Pokud se jedná o vaši první publikaci, postupujte podle kroku 6: Zabalení, publikování a sdílení. U existujících rozšíření znovu zabalte a aktualizujte je přímo na Marketplace.
Krok 7: Otestování konfigurovatelného widgetu
Vyzkoušejte si úplný pracovní postup konfigurace přidáním a konfigurací widgetu.
Přidání widgetu na řídicí panel
- Přejděte na
https://dev.azure.com/{Your_Organization}/{Your_Project}. - Přejděte na Přehled>Řídicí panely.
- Vyberte Přidejte pomůcku.
- Najděte "Hello World Widget 3 (s konfigurací)" a vyberte Přidat.
Zobrazí se výzva k konfiguraci, protože widget vyžaduje nastavení:
Konfigurace widgetu
Konfigurace přístupu prostřednictvím jedné z metod:
- Nabídka widgetu: Najeďte myší na widget, vyberte tři tečky (⋯) a pak nakonfigurujte
- Režim úprav řídicího panelu: Vyberte Upravit na řídicím panelu a pak na widgetu tlačítko Konfigurovat.
Otevře se konfigurační panel s živým náhledem uprostřed. Výběrem dotazu z rozevíracího seznamu zobrazíte okamžité aktualizace a pak výběrem možnosti Uložit změny použijete.
Krok 8: Přidání rozšířených možností konfigurace
Rozšiřte widget o více integrovaných funkcí konfigurace, jako jsou vlastní názvy a velikosti.
Povolení konfigurace názvu a velikosti
Azure DevOps nabízí dvě konfigurovatelné funkce:
| Vlastnost | Vlastnost manifestu | Účel |
|---|---|---|
| Vlastní názvy | isNameConfigurable: true |
Uživatelé můžou přepsat výchozí název widgetu. |
| Více velikostí | Více supportedSizes položek |
Uživatelé můžou měnit velikost widgetů |
Příklad rozšířeného manifestu
{
"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"]
}
}
]
}
Zobrazení nakonfigurovaných názvů
Pokud chcete zobrazit vlastní názvy widgetů, aktualizujte widget tak, aby používal 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);
}
}
Po aktualizaci rozšíření můžete nakonfigurovat název i velikost widgetu:
Znovu zabalte a aktualizujte rozšíření, abyste povolili tyto pokročilé možnosti konfigurace.
Gratulujeme! Vytvořili jste kompletní konfigurovatelný widget řídicího panelu Azure DevOps s možnostmi živého náhledu a možnostmi přizpůsobení uživatelů.