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.

Příprava a požadované nastavení pro tento kurz

Pokud chcete vytvořit rozšíření pro Azure DevOps nebo TFS, máte k dispozici určitý požadovaný software a nástroje, které budete potřebovat:

Znalost: Některé znalosti JavaScriptu, HTML, CSS jsou vyžadovány pro vývoj widgetů.

  • Organizace v Azure DevOps pro instalaci a testování widgetu najdete tady.
  • Textový editor. Pro mnoho kurzů jsme použili Visual Studio Code, které lze stáhnout zde
  • Nejnovější verze uzlu, kterou si můžete stáhnout tady
  • 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

Co najdete v tomto kurzu

  1. První část tohoto průvodce ukazuje, jak vytvořit nový widget, který vytiskne jednoduchou zprávu "Hello World".
  2. Druhá část vychází z první části přidáním volání do rozhraní REST API Azure DevOps.
  3. Třetí část vysvětluje, jak do widgetu přidat konfiguraci.

Poznámka:

Pokud jste ve spěchu a chcete získat ruce na kód hned, můžete si zde stáhnout ukázky. 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é vám poskytujeme, a s některými pokyny ke struktuře widgetů.

Část 1: Hello World

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

Overview dashboard with a sample widget

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 o sadě SDK najdete na stránce GitHubu klientské sady SDK.

Krok 2: Stránka 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, stačí aktualizovat všechny odkazy na název, na hello-world který používáte.

Váš widget je založený na HTML a je hostovaný v prvku iframe. Přidejte následující kód HTML do hello-world.htmlsouboru . Přidáme povinný odkaz na VSS.SDK.min.js soubor a zahrneme do h2 souboru prvek , 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: Váš JavaScript

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ě je níže uvedený kód, který by ve widgetu vytiskl 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ě informovat, až dokončíme načítání. Tento ovládací prvek nám umožňuje oznámit dokončení načtení po zajištění načtení závislých modulů. usePlatformStyles: true Předáváme, aby widget mohl používat základní styly Azure DevOps pro elementy HTML (například body, 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. Nezapomeňte obsah zabalit do elementu HTML s třídou widget , aby se tyto styly používaly.

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.

Vždy vss-extension.json by měl být v kořenovém adresáři složky (v tomto průvodci). 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: Logo rozšíření: logo.png

Logo se zobrazí na Marketplace a v katalogu widgetů se po instalaci rozšíření uživateli zobrazí.

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

Pro podporu TFS 2015 Update 3 potřebujete další image, která je 330 px x 160 px. Tento obrázek náhledu se zobrazí v tomto katalogu. Zvolte obrázek, pojmenujte ho preview.pnga umístěte ho do img složky jako předtím.

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: Manifest 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í.
  • 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": "vsts-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:

Vydavatele je potřeba změnit na název vydavatele. Pokud chcete vytvořit vydavatele, přejděte na web Package/Publish/Install.

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 sem odpovídající relativní cestu.
previewImageUrl Relativní cesta k obrázku náhledu, který jste přidali v kroku 4 pro zobrazení v katalogu widgetů pouze pro TFS 2015 Update 3. 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 sem 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 sem 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 nad 1x1 získá dalších 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 tuto chvíli podporujeme jenom týmové řídicí panely. Hodnota musí být project_team. Pokud v budoucnu podporujeme další obory řídicího panelu, budou tady k dispozici další možnosti, které si můžete vybrat.

Files

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í

Po napsání rozšíření je dalším krokem, jak ho dostat do Marketplace, 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 různé platformy 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 budete mít zabalenou příponu v 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, zobrazí se výzva k vytvoření vydavatele. Pokud se nezobrazí výzva k vytvoření vydavatele, posuňte se dolů na konec stránky a vyberte Možnost Publikovat rozšíření pod souvisejícími 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. Je snadné a bezpečnější, aby týmy a organizace publikovaly rozšíření v rámci společného vydavatele, ale bez nutnosti sdílet sadu přihlašovacích údajů mezi sadou uživatelů.

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í

Po vytvoření vydavatele teď můžete nahrát rozšíření na Marketplace.

  1. Najděte tlačítko 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. Budete potřebovat 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řejděte ke svému projektu v Azure DevOps. http://dev.azure.com/{yourOrganization}/{yourProject}

  2. Vyberte Přehled a pak vyberte Řídicí panely.

  3. Zvolte Přidat widget.

  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 tomto 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 přímo pod textem Hello World.

Overview dashboard with a sample widget using the REST API for WorkItemTracking.

Krok 1: 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á takto:

|--- 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  
|--- hello-world2.html              // renamed copy of hello-world.html
|--- vss-extension.json             // extension's manifest

Přidejte nový element "div" přímo pod "h2", který bude obsahovat informace o dotazu. Aktualizujte název widgetu z "HelloWorldWidget" na "HelloWorldWidget2" na řádku, na kterém voláte "VSS.register". To 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"
    ]
}

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 Visual Studio Marketplace Publishing Portalrozšíření pravým tlačítkem myši 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í TFS/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(["TFS/Dashboards/WidgetHelpers", "TFS/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 FeedbackShared Queries složce nemáte, nahraďte Shared Queries\Feedback ho v kódu cestou 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. // Do something with the query Nahraďte komentář následujícím kódem:

    // Create a list with query details                                
    var $list = $('<ul>');                                
    $list.append($('- ').text("Query Id: " + query.id));
    $list.append($('- ').text("Query Name: " + query.name));
    $list.append($('- ').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 následující:

<!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", "TFS/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($('- ').text("Query ID: " + query.id));
                                $list.append($('- ').text("Query Name: " + query.name));
                                $list.append($('- ').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/{yourOrganization}/{yourProject}. Pokud je tato stránka už otevřená, aktualizujte ji. Najetím myší na tlačítko Upravit v pravém dolním rohu vyberte tlačítko Přidat. Otevře se katalog widgetů, kde najdete widget, který jste nainstalovali. Zvolte widget a výběrem tlačítka Přidat ho přidejte do řídicího panelu.

Část 3: Hello World s konfigurací

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.

Overview dashboard live preview of the widget based on changes.

Krok 1: 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

Do souboru configuration.html přidejte následující kód HTML. V podstatě přidáme povinný odkaz na VSS. Soubor SDK.min.js a element select pro rozevírací seznam 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: JavaScript – konfigurace

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ě je níže uvedený kód, který načte konfiguraci widgetu. Otevřete soubor configuration.html a následující <script> prvek do <head>souboru .

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

        VSS.require("TFS/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 jako u widgetu, 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 vlastní Nastavení vlastnosti objektuWidgetSettings. 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);
 });

Musíte alespoň jednou upozornit architekturu změny konfigurace, aby bylo možné povolit tlačítko Uložit.

Na konci vypadá takto configuration.html :

    <!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("TFS/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: JavaScript – Implementace opětovného načtení ve widgetu

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. To 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, jak je uvedeno níže. 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 funkce 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 dotazu v getQueryInfo by měla být nahrazena nakonfigurovanou cestou dotazu, která se dá extrahovat z parametru widget Nastavení, který se předá metodě. Přidejte níže na začátek metody getQueryInfo a nahraďte pevně zakódovanou cestu dotazu "settings.queryPath".
var settings = JSON.parse(widgetSettings.customSettings.data);
if (!settings || !settings.queryPath) {
    var $container = $('#query-info-container');
    $container.empty();
    $container.text("Sorry nothing to show, please configure a query path.");

    return WidgetHelpers.WidgetStatusHelper.Success();
}

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

Obě loadreload 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.vsts-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
            }
        ],
        ...     
}

Všimněte si příspěvku pro konfiguraci widgetu, který se mírně liší od samotného widgetu. Položka příspěvku pro konfiguraci widgetu obsahuje:
  • ID pro identifikaci vašeho příspěvku To by mělo být jedinečné v rámci rozšíření.
  • Typ příspěvku. U všech konfigurací widgetů by to mělo 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á tato položka 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 jste rozšíření ještě nepublikovali, přečtěte si tuto část , ve které chcete rozšíření zabalit, publikovat a sdílet. Pokud jste rozšíření už před tímto bodem 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/{yourOrganization}/{yourProject}. Pokud je tato stránka už otevřená, aktualizujte ji. Najetím myší na tlačítko Upravit v pravém dolním rohu vyberte tlačítko Přidat. Tím by se měl otevřít katalog widgetů, ve kterém najdete widget, který jste nainstalovali. Zvolte widget a výběrem tlačítka Přidat ho přidejte do řídicího panelu.

Zobrazí se zpráva s výzvou ke konfiguraci widgetu.

Overview dashboard with a sample widget from the catalog.

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. Můžete uživatelům povolit konfiguraci, aby mohli přidat libovolný název, který chtějí do své instance widgetu. 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 následovně, 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.vsts-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.

Widget where name and size can be configured

Pokračujte a v rozevíracím seznamu zvolte 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é.

Upozorňující

Pokud odeberete již podporovanou velikost, widget se nenačte správně. Pracujeme na opravě pro budoucí verzi.

Změna názvu widgetu nezpůsobí žádnou viditelnou změnu widgetu. Důvodem je to, že naše ukázkové widgety nezobrazují název widgetu nikde. Pojďme upravit 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. Tím se 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.