Sdílet prostřednictvím


Přidání widgetu řídicího panelu

Azure DevOps Services | Azure DevOps Server 2022 – Azure DevOps Server 2019

Widgety na řídicím panelu se implementují jako příspěvky v rámci rozšíření. Jedno rozšíření může mít více příspěvků. Zjistěte, jak vytvořit rozšíření s více widgety jako příspěvky.

Tento článek je rozdělený na tři části, z nichž každá vychází z předchozího – počínaje jednoduchým widgetem a končící komplexním widgetem.

Tip

Projděte si nejnovější dokumentaci k vývoji rozšíření pomocí sady SDK rozšíření Azure DevOps.

Požadavky

  • Znalost: Některé znalosti JavaScriptu, HTML, CSS jsou vyžadovány pro vývoj widgetů.
  • Organizace v Azure DevOps.
  • Textový editor. Pro mnoho kurzů používáme Visual Studio Code.
  • Nejnovější verze uzlu.
  • Multiplatformní rozhraní příkazového řádku pro Azure DevOps (tfx-cli) pro zabalení rozšíření
    • tfx-cli lze nainstalovat pomocí npmkomponenty Node.js spuštěním příkazu npm i -g tfx-cli
  • Domovský adresář projektu. Tento adresář se označuje jako home v průběhu kurzu.

Struktura souborů přípony:

|--- 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

V tomto kurzu

  1. Část 1: Ukazuje, jak vytvořit nový widget, který vytiskne jednoduchou zprávu "Hello World".
  2. Část 2: Vychází z první části přidáním volání do rozhraní REST API Azure DevOps.
  3. Část 3: Vysvětluje, jak do widgetu přidat konfiguraci.

Poznámka:

Pokud jste ve spěchu a chcete si rovnou stáhnout kód, můžete si ukázky stáhnout. Po stažení přejděte do widgets složky a pak postupujte podle kroku 6 a kroku 7 přímo a publikujte ukázkové rozšíření, které obsahuje tři ukázkové widgety s různými složitostmi.

Začněte s některými základními styly widgetů , které poskytujeme od začátku a pokyny ke struktuře widgetů.

Část 1: Hello World

Část 1 představuje widget, který vytiskne "Hello World" pomocí JavaScriptu.

Snímek obrazovky řídicího panelu Přehled s ukázkovým widgetem

Krok 1: Získání klientské sady SDK – VSS.SDK.min.js

Základní skript VSS.SDK.min.jssady SDK umožňuje webovým rozšířením komunikovat s hostitelským rámcem Azure DevOps. Skript provádí operace, jako je inicializace, upozorňování rozšíření, načtení rozšíření nebo získání kontextu o aktuální stránce. Získejte soubor klientské sady SDK VSS.SDK.min.js a přidejte ho do webové aplikace. Umístěte ho do home/sdk/scripts složky.

K načtení sady SDK použijte příkaz npm install:

npm install vss-web-extension-sdk

Další informace najdete na stránce GitHub klientské sady SDK.

Krok 2: Nastavení stránky HTML – hello-world.html

Stránka HTML je připevnění, které obsahuje rozložení společně a obsahuje odkazy na šablony stylů CSS a JavaScript. Tento soubor můžete pojmenovat cokoli. Aktualizujte všechny odkazy na název, který hello-world používáte.

Váš widget je založený na HTML a je hostovaný v prvku iframe. hello-world.htmlDo souboru . Do souboru přidáme povinný odkaz VSS.SDK.min.js a zahrneme prvek h2 , který se aktualizuje řetězcem Hello World v nadcházejícím kroku.

<!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>

I když používáme soubor HTML, většina hlavních prvků HTML než skript a odkaz jsou ignorovány architekturou.

Krok 3: Aktualizace JavaScriptu

K vykreslení obsahu ve widgetu používáme JavaScript. V tomto článku zabalíme veškerý kód JavaScriptu do &lt;script&gt; elementu v souboru HTML. Tento kód můžete mít v samostatném javascriptovém souboru a odkazovat ho v souboru HTML. Kód vykreslí obsah. Tento javascriptový kód také inicializuje sadu SDK sady VSS, mapuje kód widgetu na název widgetu a upozorní architekturu rozšíření úspěšných nebo neúspěšných widgetů. V našem případě následující kód ve widgetu vytiskne text "Hello World". Přidejte tento script prvek do head html.

<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 inicializuje metodu handshake mezi elementem iframe, který je hostitelem widgetu a rámcem hostitele.
  • Předáme explicitNotifyLoaded: true , aby widget mohl hostitele explicitně upozornit, až se načítá. Tento ovládací prvek nám umožňuje oznámit dokončení načtení po zajištění načtení závislých modulů. Projdeme usePlatformStyles: true , aby widget mohl používat základní styly Azure DevOps pro elementy HTML (například tělo, div atd.). Pokud widget dává přednost tomu, aby tyto styly nepoužívali, mohou předat usePlatformStyles: false.
  • VSS.require slouží k načtení požadovaných knihoven skriptů VSS. Volání této metody automaticky načte obecné knihovny, jako jsou JQuery a JQueryUI. V našem případě závisíme na knihovně WidgetHelpers, která slouží ke komunikaci stavu widgetu s architekturou widgetů. Proto předáme odpovídající název TFS/Dashboards/WidgetHelpers modulu a zpětné volání .VSS.require Zpětné volání se volá po načtení modulu. Zpětné volání obsahuje zbytek kódu JavaScriptu potřebného pro widget. Na konci zpětného volání voláme VSS.notifyLoadSucceeded , abychom oznámili dokončení načítání.
  • WidgetHelpers.IncludeWidgetStyles obsahuje šablonu stylů s některými základními šablonami stylů CSS , které vám pomůžou začít. Chcete-li použít tyto styly, zabalte obsah uvnitř html elementu třídy widget.
  • VSS.register slouží k mapování funkce v JavaScriptu, která jednoznačně identifikuje widget mezi různými příspěvky ve vašem rozšíření. Název by měl odpovídat vašemu příspěvku id , jak je popsáno v kroku 5. U widgetů by funkce, která je předána VSS.register , měla vrátit objekt, který splňuje IWidget kontrakt, například vrácený objekt by měl mít vlastnost načtení, jejíž hodnota je další funkce, která má základní logiku k vykreslení widgetu. V našem případě je třeba aktualizovat text h2 prvku na "Hello World". Je to tato funkce, která se volá, když architektura widgetu vytvoří instanci widgetu. Pomocí WidgetStatusHelper widgetHelperů vrátíme WidgetStatus úspěch.

Upozorňující

Pokud název použitý k registraci widgetu neodpovídá ID příspěvku v manifestu, funkce widgetu neočekávaně funguje.

  • vss-extension.json by měl být vždy v kořenovém adresáři složky (v této příručce, HelloWorld). U všech ostatních souborů je můžete umístit do libovolné struktury, kterou chcete ve složce, stačí, abyste odkazy správně aktualizovali v souborech HTML a v manifestu vss-extension.json .

Krok 4: Aktualizace loga rozšíření: logo.png

Logo se zobrazí na Marketplace a v katalogu widgetů, jakmile uživatel nainstaluje vaše rozšíření.

Potřebujete ikonu katalogu 98 px x 98-px. Zvolte obrázek, pojmenujte ho logo.pnga umístěte ho do img složky.

Tyto image ale můžete pojmenovat, pokud se manifest rozšíření v dalším kroku aktualizuje o názvy, které používáte.

Krok 5: Vytvoření manifestu rozšíření: vss-extension.json

Každá přípona musí mít soubor manifestu přípony.

  • Přečtěte si referenční informace k manifestu rozšíření.
  • Přečtěte si další informace o bodech příspěvku v bodech rozšiřitelnosti.
  • V adresáři vytvořte soubor JSON (vss-extension.jsonnapříklad) home s následujícím obsahem:
{
    "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
        }
    ]
}

Další informace o požadovaných atributech najdete v referenčních informacích k manifestu rozšíření.

Poznámka:

Změňte vydavatele na název vydavatele. Pokud chcete vytvořit vydavatele, přečtěte si téma Balíček/ Publikování/Instalace.

Ikony

Ikony stanza určuje cestu k ikoně rozšíření v manifestu.

Příspěvky

Každá položka příspěvku definuje vlastnosti.

  • ID pro identifikaci vašeho příspěvku Toto ID by mělo být jedinečné v rámci rozšíření. Toto ID by se mělo shodovat s názvem, který jste použili v kroku 3 k registraci widgetu.
  • Typ příspěvku. Pro všechny widgety by měl být ms.vss-dashboards-web.widgettyp .
  • Pole cílů , ke kterým přispívá příspěvek. Pro všechny widgety by měl být [ms.vss-dashboards-web.widget-catalog]cíl .
  • Vlastnosti jsou objekty, které zahrnují vlastnosti pro typ příspěvku. Pro widgety jsou povinné následující vlastnosti.
Vlastnost Popis
name Název widgetu, který se má zobrazit v katalogu widgetů
description Popis widgetu, který se má zobrazit v katalogu widgetů
catalogIconUrl Relativní cesta ikony katalogu, kterou jste přidali v kroku 4 pro zobrazení v katalogu widgetů. Obrázek by měl být 98 px x 98 px. Pokud jste použili jinou strukturu složek nebo jiný název souboru, zadejte zde odpovídající relativní cestu.
previewImageUrl Relativní cesta k obrázku náhledu, který jste přidali v kroku 4 , aby se zobrazil v katalogu widgetů. Obrázek by měl být 330 px x 160 px. Pokud jste použili jinou strukturu složek nebo jiný název souboru, zadejte zde odpovídající relativní cestu.
uri Relativní cesta k souboru HTML, který jste přidali v kroku 1. Pokud jste použili jinou strukturu složek nebo jiný název souboru, zadejte zde odpovídající relativní cestu.
supportedSizes Pole velikostí podporovaných widgetem Pokud widget podporuje více velikostí, první velikost v poli je výchozí velikost widgetu. Určuje se widget size pro řádky a sloupce obsazené widgetem v mřížce řídicího panelu. Jeden řádek/sloupec odpovídá 160 px. Jakákoli dimenze větší než 1x1 získá extra 10 pixelů, které představují hřbet mezi widgety. Například widget 3x2 je 160*3+10*2 široký a 160*2+10*1 vysoký. Maximální podporovaná velikost je 4x4.
supportedScopes V současné době se podporují jenom týmové řídicí panely. Hodnota musí být project_team. Budoucí aktualizace můžou obsahovat další možnosti pro obory řídicích panelů.

Soubory

Soubory stanza uvádí soubory, které chcete zahrnout do balíčku – stránku HTML, skripty, skripty sady SDK a logo. true Pokud addressable nezahrnete jiné soubory, které nemusí být adresovatelné adresou URL.

Poznámka:

Další informace o souboru manifestu přípony, jako jsou jeho vlastnosti a co dělají, najdete v referenčních informacích k manifestu rozšíření.

Krok 6: Balení, publikování a sdílení

Až budete mít napsané rozšíření, dalším krokem, jak ho dostat do Marketplace, je zabalit všechny soubory dohromady. Všechna rozšíření jsou zabalená jako soubory .vsix kompatibilní s VSIX 2.0 – Microsoft poskytuje rozhraní příkazového řádku (CLI) pro více platforem pro zabalení rozšíření.

Získání nástroje pro balení

Rozhraní příkazového řádku pro azure DevOps (tfx-cli) můžete nainstalovat nebo aktualizovat pomocí npmkomponenty Node.js z příkazového řádku.

npm i -g tfx-cli

Zabalení rozšíření

Zabalení rozšíření do souboru .vsix je snadné, jakmile máte tfx-cli. Přejděte do domovského adresáře rozšíření a spusťte následující příkaz.

tfx extension create --manifest-globs vss-extension.json

Poznámka:

Při každé aktualizaci se musí zvýšit verze rozšíření nebo integrace.
Při aktualizaci existujícího rozšíření buď aktualizujte verzi v manifestu, nebo předejte přepínač příkazového --rev-version řádku. Tím se zvýší číslo verze opravy vašeho rozšíření a uloží se nová verze do manifestu.

Jakmile rozšíření zabalíte do souboru .vsix, můžete rozšíření publikovat na Marketplace.

Vytvoření vydavatele pro rozšíření

Všechna rozšíření, včetně rozšíření od Microsoftu, jsou identifikována jako poskytovaná vydavatelem. Pokud ještě nejste členem existujícího vydavatele, vytvořte ho.

  1. Přihlášení k portálu publikování na Webu Visual Studio Marketplace
  2. Pokud ještě nejste členem existujícího vydavatele, musíte vytvořit vydavatele. Pokud již máte vydavatele, posuňte se a vyberte Možnost Publikovat rozšíření v části Související weby.
    • Zadejte identifikátor vydavatele, například: mycompany-myteam
      • Identifikátor se používá jako hodnota atributu v souboru manifestu publisher rozšíření.
    • Zadejte zobrazovaný název vydavatele, například: My Team
  3. Zkontrolujte smlouvu vydavatele Marketplace a vyberte Vytvořit.

Teď je váš vydavatel definovaný. V budoucí verzi můžete udělit oprávnění k zobrazení a správě rozšíření vydavatele.

Publikování rozšíření v rámci běžného vydavatele zjednodušuje proces pro týmy a organizace a nabízí bezpečnější přístup. Tato metoda eliminuje potřebu distribuovat jednu sadu přihlašovacích údajů mezi více uživatelů, což zvyšuje zabezpečení a

Aktualizujte soubor manifestu vss-extension.json v ukázkách a nahraďte fiktivní ID fabrikam vydavatele vaším ID vydavatele.

Publikování a sdílení rozšíření

Teď můžete svoje rozšíření nahrát na Marketplace.

Vyberte Nahrát nové rozšíření, přejděte do zabaleného souboru .vsix a vyberte Nahrát.

Rozšíření můžete nahrát také pomocí příkazového řádku, tfx extension publish a ne tfx extension create zabalit a publikovat rozšíření v jednom kroku. Volitelně můžete rozšíření po publikování sdílet --share-with s jedním nebo více účty. Potřebujete také osobní přístupový token.

tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization

Krok 7: Přidání widgetu z katalogu

  1. Přihlaste se ke svému projektu. http://dev.azure.com/{Your_Organization}/{Your_Project}

  2. Vyberte řídicí panely přehledu>.

  3. Vyberte možnost Přidejte pomůcku.

  4. Zvýrazněte widget a pak vyberte Přidat.

    Widget se zobrazí na řídicím panelu.

Část 2: Hello World s využitím azure DevOps REST API

Widgety můžou volat libovolná rozhraní REST API v Azure DevOps pro interakci s prostředky Azure DevOps. V následujícím příkladu použijeme rozhraní REST API pro WorkItemTracking k načtení informací o existujícím dotazu a zobrazení některých informací o dotazu ve widgetu pod textem Hello World.

Snímek obrazovky řídicího panelu Přehled s ukázkovým widgetem pomocí rozhraní REST API pro WorkItemTracking

Krok 1: Přidání souboru HTML

Zkopírujte soubor hello-world.html z předchozího příkladu a přejmenujte kopii na hello-world2.html. Vaše složka teď vypadá jako v následujícím příkladu:

|--- README.md |--- node_modules
|--- SDK
|--- skripty |--- VSS. SDK.min.js |--- img |--- logo.png |--- skripty
|--- hello-world.html // html stránku, která se má použít pro widget |--- hello-world2.html // přejmenovaná kopie manifestu rozšíření hello-world.html |--- vss-extension.json ///

Chcete-li uchovávat informace o dotazu, přidejte nový div prvek pod .h2 Aktualizujte název widgetu z HelloWorldWidget řádku HelloWorldWidget2 , do kterého voláte VSS.register. Tato akce umožňuje rozhraní jednoznačně identifikovat widget v rámci rozšíření.

<!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>

Krok 2: Přístup k prostředkům Azure DevOps

Pokud chcete povolit přístup k prostředkům Azure DevOps, musí se obory zadat v manifestu rozšíření. Do manifestu vso.work přidáme obor.
Tento obor označuje, že widget potřebuje přístup jen pro čtení k dotazům a pracovním položkám. Tady najdete všechny dostupné obory. Na konec manifestu rozšíření přidejte následující kód.

{
    "scopes":[
        "vso.work"
    ]
}

Pokud chcete zahrnout další vlastnosti, měli byste je uvést explicitně, například:

{
    "name": "example-widget",
    "publisher": "example-publisher",
    "version": "1.0.0",
    "scopes": [
        "vso.work"
    ]
}

Upozorňující

Přidání nebo změna oborů po publikování rozšíření se v současné době nepodporuje. Pokud jste rozšíření už nahráli, odeberte ho z Marketplace. Přejděte na portál publikování na Webu Visual Studio Marketplace, vyberte rozšíření pravým tlačítkem a vyberte Odebrat.

Krok 3: Volání rozhraní REST API

Existuje mnoho knihoven na straně klienta, ke kterým je možné přistupovat prostřednictvím sady SDK, aby bylo možné provádět volání rozhraní REST API v Azure DevOps. Tyto knihovny se nazývají klienti REST a představují obálky JavaScriptu kolem volání Ajaxu pro všechny dostupné koncové body na straně serveru. Metody poskytované těmito klienty můžete použít místo psaní volání Ajax sami. Tyto metody mapují odpovědi rozhraní API na objekty, které může váš kód využívat.

V tomto kroku aktualizujeme VSS.require volání pro načtení AzureDevOps/WorkItemTracking/RestClient, které poskytuje klienta REST WorkItemTracking. Tento klient REST můžeme použít k získání informací o dotazu volaný Feedback pod složkou Shared Queries.

Uvnitř funkce, do VSS.registerkteré předáváme , vytvoříme proměnnou, která bude obsahovat aktuální ID projektu. K načtení dotazu potřebujeme tuto proměnnou. Vytvoříme také novou metodu getQueryInfo pro použití klienta REST. Tato metoda, která se pak volá z metody načítání.

Metoda getClient poskytuje instanci klienta REST, který potřebujeme. Metoda getQuery vrátí dotaz zabalený do příslibu. VSS.require Aktualizace vypadá takto:

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();
    });

Všimněte si použití metody Failure z WidgetStatusHelper. Umožňuje indikovat rozhraní widgetů, že došlo k chybě, a využít standardní chybové prostředí poskytované všem widgetům.

Pokud dotaz ve složce nemáte Feedback Shared Queries , nahraďte Shared Queries\Feedback v kódu cestu dotazu, který v projektu existuje.

Krok 4: Zobrazení odpovědi

Posledním krokem je vykreslení informací o dotazu uvnitř widgetu. Funkce getQuery vrátí objekt typu Contracts.QueryHierarchyItem uvnitř příslibu. V tomto příkladu zobrazíme ID dotazu, název dotazu a název tvůrce dotazu pod textem Hello World. Nahraďte komentář // Do something with the query následujícím kódem:

// 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);

Vaše konečné hello-world2.html je jako v následujícím příkladu:

<!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>

Krok 5: Aktualizace manifestu rozšíření

V tomto kroku aktualizujeme manifest rozšíření tak, aby zahrnoval položku pro náš druhý widget. Přidejte nový příspěvek do pole ve contributions vlastnosti a přidejte nový soubor hello-world2.html do pole ve vlastnosti soubory. Pro druhý widget potřebujete další obrázek náhledu. preview2.png Pojmenujte ho a umístěte ho do img složky.

{
    ...,
    "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"
    ]
}

Krok 6: Balení, publikování a sdílení

Zabalte, publikujte a sdílejte rozšíření. Pokud jste rozšíření už publikovali, můžete rozšíření znovu zabalit a přímo ho aktualizovat na Marketplace.

Krok 7: Přidání widgetu z katalogu

Teď přejděte na řídicí panel týmu na adrese https:\//dev.azure.com/{Your_Organization}/{Your_Project}. Pokud je tato stránka už otevřená, aktualizujte ji. Najetím myší na Upravit a vyberte Přidat. Otevře se katalog widgetů, kde najdete widget, který jste nainstalovali. Pokud ho chcete přidat na řídicí panel, zvolte widget a vyberte Přidat.

Část 3: Konfigurace Hello World

V části 2 tohoto průvodce jste viděli, jak vytvořit widget, který zobrazuje informace o dotazu pro pevně zakódovaný dotaz. V této části přidáme možnost nakonfigurovat dotaz tak, aby se používal místo pevně zakódovaného dotazu. Když je v režimu konfigurace, uživatel se na základě změn dostane k živému náhledu widgetu. Tyto změny se uloží do widgetu na řídicím panelu, když uživatel vybere Možnost Uložit.

Snímek obrazovky s živým náhledem řídicího panelu Přehled widgetu na základě změn

Krok 1: Přidání souboru HTML

Implementace widgetů a konfigurací widgetů jsou hodně podobné. Obě jsou implementovány v rámci rozšíření jako příspěvky. Oba používají stejný soubor SDK, VSS.SDK.min.js. Obě jsou založené na HTML, JavaScriptu a CSS.

Zkopírujte soubor html-world2.html z předchozího příkladu a přejmenujte kopii na hello-world3.html. Přidejte další soubor HTML s názvem configuration.html. Vaše složka teď vypadá jako v následujícím příkladu:

|--- 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

configuration.htmlDo souboru . V podstatě přidáme povinný odkaz na VSS.SDK.min.js soubor a select prvek rozevíracího seznamu pro výběr dotazu z přednastaveného seznamu.

    <!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: Konfigurace JavaScriptu

Pomocí JavaScriptu můžete vykreslit obsah v konfiguraci widgetu stejně jako u widgetu v kroku 3 části 1 v této příručce. Tento kód JavaScriptu vykreslí obsah, inicializuje sadu SDK sady VSS, mapuje kód konfigurace widgetu na název konfigurace a předá nastavení konfigurace do architektury. V našem případě následující kód načte konfiguraci widgetu. Otevřete soubor configuration.html a následující <script> prvek do souboru <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.requirea VSS.register hrají stejnou roli, jakou hráli pro widget, jak je popsáno v části 1. Jediným rozdílem je, že pro konfigurace widgetu by funkce, která je předána VSS.register , měla vrátit objekt, který splňuje IWidgetConfiguration kontrakt.
  • Vlastnost load kontraktu IWidgetConfiguration by měla mít funkci jako její hodnotu. Tato funkce obsahuje sadu kroků pro vykreslení konfigurace widgetu. V našem případě je potřeba aktualizovat vybranou hodnotu prvku rozevíracího seznamu s existujícím nastavením, pokud existuje. Tato funkce se zavolá, když architektura vytvoří instanci vaší instance. widget configuration
  • Vlastnost onSave kontraktu IWidgetConfiguration by měla mít funkci jako její hodnotu. Tato funkce se volá podle architektury, když uživatel vybere Možnost Uložit v podokně konfigurace. Pokud je uživatelský vstup připravený k uložení, serializujte ho do řetězce, vytvořte custom settings objekt a použijte WidgetConfigurationSave.Valid() k uložení vstupu uživatele.

V této příručce použijeme JSON k serializaci vstupu uživatele do řetězce. Můžete zvolit jakýkoli jiný způsob serializace uživatelského vstupu do řetězce. Widget je přístupný prostřednictvím vlastnosti customSettings objektu WidgetSettings . Widget musí deserializovat, což je popsáno v kroku 4.

Krok 3: JavaScript – povolení živého náhledu

Pokud chcete povolit aktualizaci živého náhledu, když uživatel vybere dotaz z rozevíracího seznamu, připojíme k tlačítku obslužnou rutinu události změny. Tato obslužná rutina upozorní architekturu, že se konfigurace změnila. Také předá customSettings , aby se použila k aktualizaci verze Preview. Aby bylo možné architekturu upozornit, notify je potřeba volat metodu widgetConfigurationContext . Přebírá dva parametry, název události, což je WidgetHelpers.WidgetEvent.ConfigurationChangev tomto případě a EventArgs objekt pro událost vytvořený z customSettings pomocné WidgetEvent.Args metody.

Do funkce přiřazené k load vlastnosti přidejte následující kód.

 $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);
 });

Revidované: Ujistěte se, že architektura bude upozorněna na změnu konfigurace aspoň jednou, aby se povolilo tlačítko Uložit .

Na konci vypadá váš configuration.html příklad jako v následujícím příkladu:

<!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>

Krok 4: Implementace opětovného načtení do widgetu – JavaScript

Nastavili jsme konfiguraci widgetu pro uložení cesty dotazu vybrané uživatelem. Teď musíme aktualizovat kód ve widgetu tak, aby místo pevně zakódované Shared Queries/Feedback konfigurace používal tuto uloženou konfiguraci z předchozího příkladu.

Otevřete soubor hello-world3.html a aktualizujte název widgetu z HelloWorldWidget2 řádku HelloWorldWidget3 , kam voláte VSS.register. Tato akce umožňuje rozhraní jednoznačně identifikovat widget v rámci rozšíření.

Funkce namapovaná na HelloWorldWidget3 prostřednictvím VSS.register aktuálně vrací objekt, který splňuje IWidget kontrakt. Vzhledem k tomu, že náš widget teď potřebuje konfiguraci, musí být tato funkce aktualizována, aby vrátila objekt, který splňuje IConfigurableWidget kontrakt. Chcete-li to provést, aktualizujte návratový příkaz tak, aby zahrnoval vlastnost s názvem znovu načíst podle následujícího kódu. Hodnota této vlastnosti je funkce, která volá metodu getQueryInfo ještě jednou. Tato metoda opětovného načtení se volá podle architektury pokaždé, když se uživatelský vstup změní tak, aby zobrazoval dynamický náhled. Tato metoda opětovného načtení se také volá při uložení konfigurace.

return {
    load: function (widgetSettings) {
        // Set your title
        var $title = $('h2.title');
        $title.text('Hello World');

        return getQueryInfo(widgetSettings);
    },
    reload: function (widgetSettings) {
        return getQueryInfo(widgetSettings);
    }
}

Pevně zakódovaná cesta getQueryInfo dotazu by měla být nahrazena nakonfigurovanou cestou dotazu, která se dá extrahovat z parametru widgetSettings předávaného metodě. Na začátek getQueryInfo metody přidejte následující kód a nahraďte pevně zakódovanou cestu settings.queryPathdotazu .

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();
}

V tuto chvíli je widget připravený k vykreslení s nakonfigurovaným nastavením.

Obě load reload vlastnosti mají podobnou funkci. Toto je případ pro většinu jednoduchých widgetů. U složitých widgetů by existovaly určité operace, které byste chtěli spustit jen jednou bez ohledu na to, kolikrát se konfigurace změní. Nebo může existovat několik náročných operací, které nemusí běžet více než jednou. Takové operace by byly součástí funkce odpovídající load vlastnosti, nikoli vlastnosti reload .

Krok 5: Aktualizace manifestu rozšíření

Otevřete soubor, vss-extension.json který bude obsahovat dvě nové položky do pole ve contributions vlastnosti. Jeden pro HelloWorldWidget3 widget a druhý pro jeho konfiguraci. Pro třetí widget potřebujete ještě další obrázek náhledu. preview3.png Pojmenujte ho a umístěte ho do img složky. Aktualizujte pole ve files vlastnosti tak, aby zahrnovalo dva nové soubory HTML, které jsme přidali v tomto příkladu.

{
    ...
    "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
            }
        ],
        ...     
}

Příspěvek pro konfiguraci widgetu se řídí trochu jiným modelem než samotný widget. Položka příspěvku pro konfiguraci widgetu obsahuje:

  • ID pro identifikaci vašeho příspěvku ID by mělo být jedinečné v rámci rozšíření.
  • Typ příspěvku. U všech konfigurací widgetů by měla být ms.vss-dashboards-web.widget-configuration
  • Pole cílů , ke kterým přispívá příspěvek. Pro všechny konfigurace widgetu má jednu položku: ms.vss-dashboards-web.widget-configuration.
  • Vlastnosti obsahující sadu vlastností, které obsahují název, popis a identifikátor URI souboru HTML použitého pro konfiguraci.

Aby bylo možné podporovat konfiguraci, je potřeba také změnit příspěvek widgetu. Pole cílů widgetu musí být aktualizováno tak, aby zahrnovalo ID konfigurace ve formuláři <publisher>.>id for the extension<.<id for the configuration contribution> V tomto případě je fabrikam.vsts-extensions-myExtensions.HelloWorldWidget.Configurationto .

Upozorňující

Pokud položka příspěvku pro konfigurovatelný widget nebude cílit na konfiguraci pomocí správného vydavatele a názvu rozšíření, jak je popsáno výše, tlačítko konfigurace se pro widget nezobrazí.

Na konci této části by soubor manifestu měl obsahovat tři widgety a jednu konfiguraci. Tady můžete získat úplný manifest z ukázky.

Krok 6: Balení, publikování a sdílení

Pokud vaše rozšíření není publikované, přečtěte si tuto část. Pokud jste rozšíření už publikovali, můžete rozšíření znovu zabalit a přímo ho aktualizovat na Marketplace.

Krok 7: Přidání widgetu z katalogu

Teď přejděte na řídicí panel týmu na adrese https://dev.azure.com/{Your_Organization}/{Your_Project}. Pokud je tato stránka už otevřená, aktualizujte ji. Najetím myší na Upravit a vyberte Přidat. Tato akce by měla otevřít katalog widgetů, kde najdete widget, který jste nainstalovali. Pokud chcete widget přidat na řídicí panel, zvolte widget a vyberte Přidat.

Zpráva podobná následující po vás požádá o konfiguraci widgetu.

Snímek obrazovky řídicího panelu Přehled s ukázkovým widgetem z katalogu

Existují dva způsoby konfigurace widgetů. Jedním z nich je najetí myší na widget, vybrat tři tečky, které se zobrazí v pravém horním rohu, a pak vyberte Konfigurovat. Druhým je vybrat tlačítko Upravit v pravém dolním rohu řídicího panelu a pak vybrat tlačítko konfigurovat, které se zobrazí v pravém horním rohu widgetu. Na pravé straně se otevře prostředí konfigurace a uprostřed se zobrazí náhled widgetu. Pokračujte a v rozevíracím seznamu zvolte dotaz. V živém náhledu se zobrazují aktualizované výsledky. Vyberte Uložit a widget zobrazí aktualizované výsledky.

Krok 8: Konfigurace dalších (volitelné)

Do další konfigurace můžete přidat tolik elementů formuláře HTML, kolik potřebujete configuration.html . K dispozici jsou dvě konfigurovatelné funkce: název widgetu a velikost widgetu.

Ve výchozím nastavení se název, který zadáte pro widget v manifestu rozšíření, uloží jako název widgetu pro každou instanci widgetu, která se někdy přidá na řídicí panel. Uživatelům můžete povolit konfiguraci, aby mohli do své instance widgetu přidat libovolný název. Pokud chcete takovou konfiguraci povolit, přidejte isNameConfigurable:true do oddílu vlastností widgetu v manifestu rozšíření.

Pokud do pole v manifestu supportedSizes rozšíření zadáte více než jednu položku widgetu, můžou uživatelé také nakonfigurovat velikost widgetu.

Manifest rozšíření třetí ukázky v této příručce by vypadal jako v následujícím příkladu, pokud povolíme konfiguraci názvu a velikosti widgetu:

{
    ...
    "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"]
             }
         },
         ...
    ]
}

S předchozí změnou znovu zabalte a aktualizujte rozšíření. Aktualizujte řídicí panel s tímto widgetem (Hello World Widget 3 (s konfigurací)). Otevřete režim konfigurace widgetu. Teď byste měli být schopni zobrazit možnost změnit název a velikost widgetu.

Snímek obrazovky znázorňující widget, kde je možné nakonfigurovat název a velikost

V rozevíracím seznamu vyberte jinou velikost. Zobrazí se změna velikosti živého náhledu. Uložte změnu a widget na řídicím panelu se změní také.

Změna názvu widgetu nemá za následek žádnou viditelnou změnu widgetu, protože naše ukázkové widgety nikde nezobrazují název widgetu. Upravme vzorový kód tak, aby zobrazoval název widgetu místo pevně zakódovaného textu "Hello World".

Uděláte to tak, že nahradíte pevně zakódovaný text "Hello World" widgetSettings.name na řádku, na kterém nastavíme text h2 prvku. Tato akce zajistí, že se název widgetu zobrazí při každém načtení widgetu při aktualizaci stránky. Vzhledem k tomu, že chceme, aby se živá verze Preview aktualizovala při každé změně konfigurace, měli bychom do části našeho kódu také přidat stejný kód reload . Poslední návratový příkaz hello-world3.html je následující:

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);
    }
}

Znovu zabalte a aktualizujte rozšíření znovu. Aktualizujte řídicí panel s tímto widgetem.

Všechny změny názvu widgetu v režimu konfigurace teď aktualizují název widgetu.