Udostępnij za pośrednictwem


Dodawanie widżetu pulpitu nawigacyjnego

Azure DevOps Services | Azure DevOps Server 2022 — Azure DevOps Server 2019

Widgets na pulpicie nawigacyjnym są implementowane jako kontrybucje w frameworku rozszerzeń. Jedna rozszerzenie może mieć wiele wkładów. Dowiedz się, jak utworzyć rozszerzenie z wieloma widżetami jako wkłady.

Ten artykuł jest podzielony na trzy części, z których każdy jest oparty na poprzedniej części. Zaczynasz od prostego widżetu i kończysz się kompleksowym widżetem.

Napiwek

Zapoznaj się z naszą najnowszą dokumentacją dotyczącą rozwoju rozszerzeń przy użyciu Azure DevOps Extension SDK.

Wymagania wstępne

Wymaganie Opis
Wiedza na temat programowania Znajomość języków JavaScript, HTML i CSS na potrzeby programowania widżetów
Organizacja usługi Azure DevOps Tworzenie organizacji
Edytor tekstu Do samouczków używamy programu Visual Studio Code
Node.js Najnowsza wersja Node.js
Międzyplatformowy CLI tfx-cli do pakowania rozszerzeń
Zainstaluj przy użyciu: npm i -g tfx-cli
Katalog projektu Katalog główny z tą strukturą po ukończeniu samouczka:

|--- README.md
|--- sdk
|--- node_modules
|--- scripts
|--- VSS.SDK.min.js
|--- img
|--- logo.png
|--- scripts
|--- hello-world.html // html page for your widget
|--- vss-extension.json // extension manifest

Samouczek — omówienie

W tym samouczku przedstawiono programowanie widżetów za pomocą trzech progresywnych przykładów:

Część Ukierunkowanie Czego się uczysz
Część 1. Witaj świecie Tworzenie podstawowego widżetu Tworzenie widżetu, który wyświetla tekst
Część 2. Integracja interfejsu API REST Wywołania interfejsu API usługi Azure DevOps Dodawanie funkcji interfejsu API REST w celu pobierania i wyświetlania danych
Część 3. Konfiguracja widżetu Dostosowywanie użytkownika Implementowanie opcji konfiguracji widżetu

Napiwek

Pomiń samouczek: Pobierz kompletne przykładowe rozszerzenie, przejdź do folderu i przejdź do widgetskroku 6 , aby opublikować trzy gotowe do użycia widżety przykładowe.

Przed rozpoczęciem zapoznaj się z podstawowymi stylami widżetów i wskazówkami strukturalnymi, które udostępniamy.

Część 1. Witaj świecie

Utwórz podstawowy widżet, który wyświetla tekst "Hello World" przy użyciu języka JavaScript. W ramach tej podstawy przedstawiono podstawowe pojęcia dotyczące tworzenia widżetów.

Zrzut ekranu przedstawiający pulpit nawigacyjny Przegląd z przykładowym widżetem.

Krok 1. Instalowanie zestawu SDK klienta

Zestaw VSS SDK umożliwia widżetowi komunikowanie się z usługą Azure DevOps. Zainstaluj go przy użyciu narzędzia npm:

npm install vss-web-extension-sdk

VSS.SDK.min.js Skopiuj plik z vss-web-extension-sdk/lib folderu do home/sdk/scripts folderu.

Aby uzyskać więcej dokumentacji zestawu SDK, zobacz stronę zestawu SDK klienta w witrynie GitHub.

Krok 2. Tworzenie struktury HTML

Utwórz hello-world.html w katalogu projektu. Ten plik zawiera układ widżetu i odwołania do wymaganych skryptów.

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

Widżety są uruchamiane wewnątrz iframe, więc większość elementów nagłówka HTML z wyjątkiem <script> i <link> jest ignorowana przez framework.

Krok 3. Dodawanie widżetu JavaScript

Aby zaimplementować funkcjonalność widżetu, dodaj ten skrypt do <head> sekcji pliku HTML:

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

    VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
        WidgetHelpers.IncludeWidgetStyles();
        VSS.register("HelloWorldWidget", function () {                
            return {
                load: function (widgetSettings) {
                    var $title = $('h2.title');
                    $title.text('Hello World');

                    return WidgetHelpers.WidgetStatusHelper.Success();
                }
            };
        });
        VSS.notifyLoadSucceeded();
    });
</script>

Kluczowe składniki języka JavaScript

Funkcja Przeznaczenie
VSS.init() Inicjuje komunikację między widżetem a usługą Azure DevOps
VSS.require() Ładuje wymagane biblioteki zestawu SDK i pomocników widżetów
VSS.register() Rejestruje widżet przy użyciu unikatowego identyfikatora
WidgetHelpers.IncludeWidgetStyles() Stosuje domyślne style usługi Azure DevOps
VSS.notifyLoadSucceeded() Powiadamia platformę o pomyślnym zakończeniu ładowania

Ważne

Nazwa widżetu w VSS.register() musi być zgodna z id w manifeście rozszerzenia (krok 5).

Krok 4. Dodawanie obrazów rozszerzeń

Utwórz wymagane obrazy dla rozszerzenia:

  • Logo rozszerzenia: obraz 98x98 pikseli o nazwie logo.png w folderze img
  • Ikona wykazu widżetów: obraz o rozmiarze 98 x 98 pikseli o nazwie CatalogIcon.png w folderze img
  • Podgląd widżetu: obraz 330x160 pikseli o nazwie preview.png w folderze img

Te obrazy są wyświetlane w witrynie Marketplace i katalogu widżetów podczas przeglądania dostępnych rozszerzeń przez użytkowników.

Krok 5. Tworzenie manifestu rozszerzenia

Utwórz vss-extension.json w katalogu głównym projektu. Ten plik definiuje metadane i kontrybucje rozszerzenia.

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

Ważne

Zastąp "publisher": "fabrikam" rzeczywistą nazwą wydawcy. Dowiedz się, jak utworzyć wydawcę.

Podstawowe właściwości manifestu

Sekcja Przeznaczenie
Podstawowe informacje Nazwa rozszerzenia, wersja, opis i wydawca
Ikony Ścieżki do zasobów wizualnych rozszerzenia
Składki Definicje widżetów, w tym identyfikator, typ i właściwości
Pliki Wszystkie pliki do uwzględnienia w pakiecie rozszerzenia

Aby uzyskać pełną dokumentację manifestu, zobacz Odniesienie do manifestu rozszerzenia.

Krok 6. Pakowanie i publikowanie rozszerzenia

Spakuj rozszerzenie i opublikuj je w witrynie Visual Studio Marketplace.

Zainstaluj narzędzie do pakowania

npm i -g tfx-cli

Tworzenie pakietu rozszerzenia

W katalogu projektu uruchom polecenie:

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

Ta akcja powoduje utworzenie pliku zawierającego .vsix spakowane rozszerzenie.

Konfigurowanie wydawcy

  1. Przejdź do portalu publikowania Visual Studio Marketplace.
  2. Zaloguj się i utwórz wydawcę, jeśli go nie masz.
  3. Wybierz unikatowy identyfikator wydawcy (używany w pliku manifestu).
  4. Zaktualizuj element vss-extension.json tak, aby używał nazwy wydawcy zamiast "fabrikam".

Prześlij swoje rozszerzenie

  1. W portalu wydawniczym wybierz Prześlij nowe rozszerzenie.
  2. Wybierz plik .vsix i załaduj go.
  3. Udostępnij rozszerzenie w organizacji usługi Azure DevOps.

Alternatywnie użyj wiersza polecenia:

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

Napiwek

Użyj polecenia --rev-version , aby automatycznie zwiększać numer wersji podczas aktualizowania istniejącego rozszerzenia.

Krok 7. Instalowanie i testowanie widżetu

Aby przetestować, dodaj widżet do pulpitu nawigacyjnego:

  1. Przejdź do projektu usługi Azure DevOps: https://dev.azure.com/{Your_Organization}/{Your_Project}.
  2. Przejdź do sekcji Przegląd>Pulpity nawigacyjne.
  3. Wybierz Dodaj widżet.
  4. Znajdź widżet w katalogu i wybierz pozycję Dodaj.

Widżet "Hello World" pojawia się na pulpicie nawigacyjnym, wyświetlając skonfigurowany tekst.

Następny krok: Przejdź do części 2 , aby dowiedzieć się, jak zintegrować interfejsy API REST usługi Azure DevOps z widżetem.

Część 2. Hello World z interfejsem API REST usługi Azure DevOps

Rozszerz widżet, aby korzystać z danych usługi Azure DevOps przy użyciu interfejsów API REST. W tym przykładzie pokazano, jak pobierać informacje o zapytaniach i wyświetlać je dynamicznie w widżecie.

W tej części użyj interfejsu API REST do śledzenia zadań roboczych, aby pobrać informacje o istniejącym zapytaniu i wyświetlić jego szczegóły poniżej tekstu "Hello World".

Zrzut ekranu przedstawiający pulpit nawigacyjny Przegląd z przykładowym widżetem przy użyciu interfejsu API REST dla rozwiązania WorkItemTracking.

Krok 1. Tworzenie rozszerzonego pliku HTML

Utwórz nowy plik widżetu, który bazuje na poprzednim przykładzie. Skopiuj hello-world.html i zmień jego nazwę na hello-world2.html. Struktura projektu obejmuje teraz następujące elementy:

|--- README.md
|--- node_modules
|--- sdk/
    |--- scripts/
        |--- VSS.SDK.min.js
|--- img/
    |--- logo.png
|--- scripts/
|--- hello-world.html               // Part 1 widget
|--- hello-world2.html              // Part 2 widget (new)
|--- vss-extension.json             // Extension manifest

Aktualizowanie struktury HTML widżetu

Wprowadź następujące zmiany w hello-world2.html:

  1. Dodawanie kontenera dla danych zapytań: dołącz nowy <div> element do wyświetlania informacji o kwerendzie.
  2. Zaktualizuj identyfikator widżetu: zmień nazwę widżetu z HelloWorldWidget na HelloWorldWidget2 w celu uzyskania unikatowej identyfikacji.
<!DOCTYPE html>
<html>
    <head>
        <script src="sdk/scripts/VSS.SDK.min.js"></script>
        <script type="text/javascript">
            VSS.init({
                explicitNotifyLoaded: true,
                usePlatformStyles: true
            });

            VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
                WidgetHelpers.IncludeWidgetStyles();
                VSS.register("HelloWorldWidget2", function () {
                    return {
                        load: function (widgetSettings) {
                            var $title = $('h2.title');
                            $title.text('Hello World');

                            return WidgetHelpers.WidgetStatusHelper.Success();
                        }
                    }
                });
                VSS.notifyLoadSucceeded();
            });
        </script>
    </head>
    <body>
        <div class="widget">
            <h2 class="title"></h2>
            <div id="query-info-container"></div>
        </div>
    </body>
</html>

Krok 2. Konfigurowanie uprawnień dostępu do interfejsu API

Przed wywołaniami interfejsu API REST skonfiguruj wymagane uprawnienia w manifeście rozszerzenia.

Dodawanie zakresu pracy

Zakres vso.work udziela dostępu w trybie tylko do odczytu do elementów roboczych i zapytań. Dodaj ten zakres do elementu vss-extension.json:

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

Kompletny przykład manifestu

Aby uzyskać kompletny manifest z innymi właściwościami, utwórz strukturę w następujący sposób:

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

Ważne

Ograniczenia zakresu: dodawanie lub zmienianie zakresów po opublikowaniu nie jest obsługiwane. Jeśli rozszerzenie zostało już opublikowane, musisz najpierw usunąć je z witryny Marketplace. Przejdź do portalu publikacyjnego Visual Studio Marketplace, znajdź rozszerzenie i wybierz Usuń.

Krok 3. Implementowanie integracji interfejsu API REST

Usługa Azure DevOps udostępnia biblioteki klienta REST języka JavaScript za pośrednictwem zestawu SDK. Te biblioteki opakowują wywołania AJAX i mapują odpowiedzi interfejsu API na obiekty do użycia.

Aktualizowanie widżetu JavaScript

Zastąp wywołanie VSS.require w hello-world2.html aby uwzględnić klienta REST śledzenia elementów roboczych.

VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"], 
    function (WidgetHelpers, WorkItemTrackingRestClient) {
        WidgetHelpers.IncludeWidgetStyles();
        VSS.register("HelloWorldWidget2", function () { 
            var projectId = VSS.getWebContext().project.id;

            var getQueryInfo = function (widgetSettings) {
                // Get a WIT client to make REST calls to Azure DevOps Services
                return WorkItemTrackingRestClient.getClient().getQuery(projectId, "Shared Queries/Feedback")
                    .then(function (query) {
                        // Process query data (implemented in Step 4)

                        return WidgetHelpers.WidgetStatusHelper.Success();
                    }, function (error) {                            
                        return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
                    });
            }

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

                    return getQueryInfo(widgetSettings);
                }
            }
        });
        VSS.notifyLoadSucceeded();
    });

Kluczowe szczegóły implementacji

Składnik Przeznaczenie
WorkItemTrackingRestClient.getClient() Pobiera wystąpienie klienta śledzenia zadań roboczych REST
getQuery() Pobiera informacje o zapytaniach opakowane w obietnicę
WidgetStatusHelper.Failure() Zapewnia spójną obsługę błędów w przypadku awarii widżetów
projectId Bieżący kontekst projektu wymagany dla wywołań interfejsu API

Napiwek

Niestandardowe ścieżki zapytań: jeśli nie masz zapytania "Opinia" w obszarze "Udostępnione zapytania", zastąp "Shared Queries/Feedback" ścieżką do dowolnej kwerendy, która istnieje w projekcie.

Krok 4. Wyświetlanie danych odpowiedzi interfejsu API

Renderuj informacje o kwerendzie w widżecie, przetwarzając odpowiedź interfejsu API REST.

Dodawanie renderowania danych zapytań

Zastąp komentarz następującą implementacją // Process query data :

// Create a list with query details                                
var $list = $('<ul>');                                
$list.append($('<li>').text("Query ID: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));

// Append the list to the query-info-container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);

Metoda getQuery() zwraca Contracts.QueryHierarchyItem obiekt z właściwościami metadanych zapytania. W tym przykładzie są wyświetlane trzy kluczowe informacje poniżej tekstu "Hello World".

Kompletny przykład roboczy

hello-world2.html Końcowy plik powinien wyglądać następująco:

<!DOCTYPE html>
<html>
<head>    
    <script src="sdk/scripts/VSS.SDK.min.js"></script>
    <script type="text/javascript">
        VSS.init({
            explicitNotifyLoaded: true,
            usePlatformStyles: true
        });

        VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"], 
            function (WidgetHelpers, WorkItemTrackingRestClient) {
                WidgetHelpers.IncludeWidgetStyles();
                VSS.register("HelloWorldWidget2", function () {                
                    var projectId = VSS.getWebContext().project.id;

                    var getQueryInfo = function (widgetSettings) {
                        // Get a WIT client to make REST calls to Azure DevOps Services
                        return WorkItemTrackingRestClient.getClient().getQuery(projectId, "Shared Queries/Feedback")
                            .then(function (query) {
                                // Create a list with query details                                
                                var $list = $('<ul>');
                                $list.append($('<li>').text("Query ID: " + query.id));
                                $list.append($('<li>').text("Query Name: " + query.name));
                                $list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));

                                // Append the list to the query-info-container
                                var $container = $('#query-info-container');
                                $container.empty();
                                $container.append($list);

                                // Use the widget helper and return success as Widget Status
                                return WidgetHelpers.WidgetStatusHelper.Success();
                            }, function (error) {
                                // Use the widget helper and return failure as Widget Status
                                return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
                            });
                    }

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

                            return getQueryInfo(widgetSettings);
                        }
                    }
                });
            VSS.notifyLoadSucceeded();
        });       
    </script>

</head>
<body>
    <div class="widget">
        <h2 class="title"></h2>
        <div id="query-info-container"></div>
    </div>
</body>
</html>

Krok 5. Aktualizowanie manifestu rozszerzenia

Aby udostępnić go w katalogu widżetów, dodaj nowy widżet do manifestu rozszerzenia.

Dodaj drugi wkład widżetu

Zaktualizuj vss-extension.json element, aby uwzględnić widżet zgodny z API REST. Dodaj ten wkład do tablicy contributions :

{
    "contributions": [
        // ...existing HelloWorldWidget contribution...,
        {
            "id": "HelloWorldWidget2",
            "type": "ms.vss-dashboards-web.widget",
            "targets": [
                "ms.vss-dashboards-web.widget-catalog"
            ],
            "properties": {
                "name": "Hello World Widget 2 (with API)",
                "description": "My second widget",
                "previewImageUrl": "img/preview2.png",
                "uri": "hello-world2.html",
                "supportedSizes": [
                    {
                        "rowSpan": 1,
                        "columnSpan": 2
                    }
                ],
                "supportedScopes": ["project_team"]
            }
        }
    ],
    "files": [
        {
            "path": "hello-world.html",
            "addressable": true
        },
        {
            "path": "hello-world2.html",
            "addressable": true
        },
        {
            "path": "sdk/scripts",
            "addressable": true
        },
        {
            "path": "img",
            "addressable": true
        }
    ],
    "scopes": [
        "vso.work"
    ]
}

Napiwek

Obraz podglądupreview2.png: utwórz obraz (330x160 pikseli) i umieść go w img folderze, aby pokazać użytkownikom, jak wygląda widżet w katalogu.

Krok 6. Pakowanie, publikowanie i udostępnianie

Pakuj, publikuj i udostępniaj swoje rozszerzenie. Jeśli rozszerzenie zostało już opublikowane, możesz ponownie spakować je i zaktualizować bezpośrednio w witrynie Marketplace.

Krok 7. Testowanie widżetu interfejsu API REST

Aby wyświetlić akcję integracji interfejsu API REST, dodaj nowy widżet do pulpitu nawigacyjnego:

  1. Przejdź do projektu usługi Azure DevOps: https://dev.azure.com/{Your_Organization}/{Your_Project}.
  2. Wybierz Przegląd>Pulpity.
  3. Wybierz Dodaj widżet.
  4. Znajdź pozycję "Hello World Widget 2 (z interfejsem API)" i wybierz pozycję Dodaj.

Rozszerzony widżet wyświetla tekst "Hello World" i informacje o zapytaniu na żywo z projektu usługi Azure DevOps.

Następne kroki: Przejdź do części 3 , aby dodać opcje konfiguracji, które umożliwiają użytkownikom dostosowanie zapytania do wyświetlenia.

Część 3. Konfigurowanie środowiska Hello World

Rozwiń część 2, dodając możliwości konfiguracji użytkownika do widżetu. Zamiast trwale kodować ścieżkę zapytania, utwórz interfejs konfiguracji, który pozwala użytkownikom wybrać, które zapytanie ma być wyświetlane, z funkcją podglądu na żywo.

W tej części pokazano, jak tworzyć konfigurowalne widżety, które użytkownicy mogą dostosowywać do swoich konkretnych potrzeb, jednocześnie zapewniając opinię w czasie rzeczywistym podczas konfigurowania.

Zrzut ekranu przedstawiający podgląd na żywo pulpitu nawigacyjnego podsumowania widżetu w oparciu o zmiany.

Krok 1. Tworzenie plików konfiguracji

Konfiguracje widżetów współdzielą wiele podobieństw z widżetami — używają tych samych wzorców zestawu SDK, struktury HTML i języka JavaScript, ale służą do różnych celów w ramach struktury rozszerzeń.

Konfigurowanie struktury projektu

Aby obsługiwać konfigurację widżetu, utwórz dwa nowe pliki:

  1. Skopiuj hello-world2.html i zmień jego nazwę na hello-world3.html, twój konfigurowalny widżet.
  2. Utwórz nowy plik o nazwie configuration.html, który obsługuje interfejs konfiguracji.

Struktura projektu obejmuje teraz następujące elementy:

|--- README.md
|--- sdk/    
    |--- node_modules           
    |--- scripts/
        |--- VSS.SDK.min.js       
|--- img/                        
    |--- logo.png                           
|--- scripts/          
|--- configuration.html              // New: Configuration interface
|--- hello-world.html               // Part 1: Basic widget  
|--- hello-world2.html              // Part 2: REST API widget
|--- hello-world3.html              // Part 3: Configurable widget (new)
|--- vss-extension.json             // Extension manifest

Tworzenie interfejsu konfiguracji

Dodaj tę strukturę HTML do configuration.html, który tworzy selektor listy rozwijanej do wybierania zapytań.

<!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. Implementowanie konfiguracji języka JavaScript

JavaScript konfiguracji jest zgodny z tym samym wzorcem inicjowania co widżety, ale implementuje IWidgetConfiguration kontrakt zamiast kontraktu podstawowego IWidget.

Dodawanie logiki konfiguracji

Wstaw ten skrypt do sekcji <head>configuration.html.

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

    VSS.require(["AzureDevOps/Dashboards/WidgetHelpers"], function (WidgetHelpers) {
        VSS.register("HelloWorldWidget.Configuration", function () {   
            var $queryDropdown = $("#query-path-dropdown"); 

            return {
                load: function (widgetSettings, widgetConfigurationContext) {
                    var settings = JSON.parse(widgetSettings.customSettings.data);
                    if (settings && settings.queryPath) {
                         $queryDropdown.val(settings.queryPath);
                     }

                    return WidgetHelpers.WidgetStatusHelper.Success();
                },
                onSave: function() {
                    var customSettings = {
                        data: JSON.stringify({
                                queryPath: $queryDropdown.val()
                            })
                    };
                    return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings); 
                }
            }
        });
        VSS.notifyLoadSucceeded();
    });
</script>

Szczegóły kontraktu konfiguracji

Kontrakt IWidgetConfiguration wymaga następujących kluczowych funkcji:

Funkcja Przeznaczenie Po wywołaniu
load() Zainicjalizuj interfejs użytkownika konfiguracji z istniejącymi ustawieniami Gdy otworzy się okno dialogowe konfiguracji
onSave() Serializowanie danych wejściowych użytkownika i weryfikowanie ustawień Gdy użytkownik wybierze pozycję Zapisz

Napiwek

Serializacja danych: w tym przykładzie użyto formatu JSON do serializacji ustawień. Widżet uzyskuje dostęp do tych ustawień za pośrednictwem metody widgetSettings.customSettings.data i musi odpowiednio je deserializować.

Krok 3. Włączanie funkcji podglądu na żywo

Podgląd na żywo umożliwia użytkownikom natychmiastowe wyświetlanie zmian widżetów w miarę modyfikowania ustawień konfiguracji, przesyłania błyskawicznych opinii przed zapisaniem.

Implementowanie powiadomień o zmianach

Aby włączyć wersję zapoznawcza na żywo, dodaj tę procedurę obsługi zdarzeń w load funkcji:

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

Kompletny plik konfiguracji

Twój ostateczny configuration.html powinien wyglądać w ten sposób:

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

Ważne

Włącz przycisk Zapisz: platforma wymaga co najmniej jednego powiadomienia o zmianie konfiguracji, aby włączyć przycisk Zapisz . Procedura obsługi zdarzeń zmiany zapewnia, że ta akcja występuje po wybraniu opcji przez użytkowników.

Krok 4. Konfigurowanie widżetu

Przekształć widżet z części 2, aby używać danych konfiguracji zamiast wartości zakodowanych na twardo. Ten krok wymaga wdrożenia kontraktu IConfigurableWidget .

Aktualizowanie rejestracji widżetu

W hello-world3.htmlpliku wprowadź następujące zmiany:

  1. Aktualizowanie identyfikatora widżetu: zmień wartość z HelloWorldWidget2 na HelloWorldWidget3.
  2. Dodaj funkcję ponownego ładowania: zaimplementujIConfigurableWidget kontrakt.
return {
    load: function (widgetSettings) {
        // Set your title
        var $title = $('h2.title');
        $title.text('Hello World');

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

Obsługa danych konfiguracji

Zaktualizuj funkcję tak getQueryInfo , aby korzystała z ustawień konfiguracji zamiast zakodowanych ścieżek zapytań:

var settings = JSON.parse(widgetSettings.customSettings.data);
if (!settings || !settings.queryPath) {
    var $container = $('#query-info-container');
    $container.empty();
    $container.text("Please configure a query path to display data.");

    return WidgetHelpers.WidgetStatusHelper.Success();
}

Różnice cyklu życia widżetu

Funkcja Przeznaczenie Wskazówki dotyczące użycia
load() Początkowe renderowanie widżetów i jednorazowa konfiguracja Intensywne operacje, inicjowanie zasobów
reload() Aktualizowanie widżetu przy użyciu nowej konfiguracji Uproszczone aktualizacje, odświeżanie danych

Napiwek

Optymalizacja wydajności: należy użyć w load() przypadku kosztownych operacji, które muszą być uruchamiane tylko raz, i reload() w celu szybkiego aktualizowania w przypadku zmiany konfiguracji.

(Opcjonalnie) Dodaj lightbox dla szczegółowych informacji

Widżety pulpitu nawigacyjnego mają ograniczoną ilość miejsca, co utrudnia wyświetlanie kompleksowych informacji. Lightbox zapewnia eleganckie rozwiązanie, wyświetlając szczegółowe dane w modalnej nakładce bez opuszczania konsoli.

Dlaczego warto używać lightboxu w widżetach?

Korzyść Opis
Wydajne wykorzystanie miejsca Zachowaj kompaktowanie widżetu, oferując szczegółowe widoki
Środowisko użytkownika Zachowanie kontekstu pulpitu nawigacyjnego przy wyświetlaniu więcej informacji
Stopniowe ujawnianie Pokaż dane podsumowania w widżecie, szczegóły na żądanie
dynamiczny projekt Dostosowywanie do różnych rozmiarów ekranu i konfiguracji widżetów

Implementowanie elementów z możliwością klikania

Zaktualizuj renderowanie danych zapytania, aby uwzględnić elementy z możliwością kliknięcia, które wyzwalają lightbox:

// Create a list with clickable query details
var $list = $('<ul class="query-summary">');                                
$list.append($('<li>').text("Query ID: " + query.id));
$list.append($('<li>').text("Query Name: " + query.name));
$list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>"));

// Add a clickable element to open detailed view
var $detailsLink = $('<button class="details-link">View Details</button>');
$detailsLink.on('click', function() {
    showQueryDetails(query);
});

// Append to the container
var $container = $('#query-info-container');
$container.empty();
$container.append($list);
$container.append($detailsLink);

Utwórz funkcjonalność lightbox

Dodaj tę implementację lightbox do widżetu JavaScript:

function showQueryDetails(query) {
    // Create lightbox overlay
    var $overlay = $('<div class="lightbox-overlay">');
    var $lightbox = $('<div class="lightbox-content">');
    
    // Add close button
    var $closeBtn = $('<button class="lightbox-close">&times;</button>');
    $closeBtn.on('click', function() {
        $overlay.remove();
    });
    
    // Create detailed content
    var $content = $('<div class="query-details">');
    $content.append($('<h3>').text(query.name || 'Query Details'));
    $content.append($('<p>').html('<strong>ID:</strong> ' + query.id));
    $content.append($('<p>').html('<strong>Path:</strong> ' + query.path));
    $content.append($('<p>').html('<strong>Created:</strong> ' + (query.createdDate ? new Date(query.createdDate).toLocaleDateString() : 'Unknown')));
    $content.append($('<p>').html('<strong>Modified:</strong> ' + (query.lastModifiedDate ? new Date(query.lastModifiedDate).toLocaleDateString() : 'Unknown')));
    $content.append($('<p>').html('<strong>Created By:</strong> ' + (query.createdBy ? query.createdBy.displayName : 'Unknown')));
    $content.append($('<p>').html('<strong>Modified By:</strong> ' + (query.lastModifiedBy ? query.lastModifiedBy.displayName : 'Unknown')));
    
    if (query.queryType) {
        $content.append($('<p>').html('<strong>Type:</strong> ' + query.queryType));
    }
    
    // Assemble lightbox
    $lightbox.append($closeBtn);
    $lightbox.append($content);
    $overlay.append($lightbox);
    
    // Add to document and show
    $('body').append($overlay);
    
    // Close on overlay click
    $overlay.on('click', function(e) {
        if (e.target === $overlay[0]) {
            $overlay.remove();
        }
    });
    
    // Close on Escape key
    $(document).on('keydown.lightbox', function(e) {
        if (e.keyCode === 27) { // Escape key
            $overlay.remove();
            $(document).off('keydown.lightbox');
        }
    });
}

Dodaj styl lightbox

Uwzględnij style CSS dla kontrolki lightbox w sekcji HTML <head> widżetu:

<style>
.query-summary {
    list-style: none;
    padding: 0;
    margin: 10px 0;
}

.query-summary li {
    padding: 2px 0;
    font-size: 12px;
}

.details-link {
    background: #0078d4;
    color: white;
    border: none;
    padding: 4px 8px;
    font-size: 11px;
    cursor: pointer;
    border-radius: 2px;
    margin-top: 8px;
}

.details-link:hover {
    background: #106ebe;
}

.lightbox-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
}

.lightbox-content {
    background: white;
    border-radius: 4px;
    padding: 20px;
    max-width: 500px;
    max-height: 80vh;
    overflow-y: auto;
    position: relative;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.lightbox-close {
    position: absolute;
    top: 10px;
    right: 15px;
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: #666;
    line-height: 1;
}

.lightbox-close:hover {
    color: #000;
}

.query-details h3 {
    margin-top: 0;
    color: #323130;
}

.query-details p {
    margin: 8px 0;
    font-size: 14px;
    line-height: 1.4;
}
</style>

Ulepszona implementacja widżetu

Kompletny ulepszony widżet z funkcją lightbox:

<!DOCTYPE html>
<html>
<head>    
    <script src="sdk/scripts/VSS.SDK.min.js"></script>
    <style>
        /* Lightbox styles from above */
        .query-summary {
            list-style: none;
            padding: 0;
            margin: 10px 0;
        }
        
        .query-summary li {
            padding: 2px 0;
            font-size: 12px;
        }
        
        .details-link {
            background: #0078d4;
            color: white;
            border: none;
            padding: 4px 8px;
            font-size: 11px;
            cursor: pointer;
            border-radius: 2px;
            margin-top: 8px;
        }
        
        .details-link:hover {
            background: #106ebe;
        }
        
        .lightbox-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.7);
            z-index: 10000;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        .lightbox-content {
            background: white;
            border-radius: 4px;
            padding: 20px;
            max-width: 500px;
            max-height: 80vh;
            overflow-y: auto;
            position: relative;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        }
        
        .lightbox-close {
            position: absolute;
            top: 10px;
            right: 15px;
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            color: #666;
            line-height: 1;
        }
        
        .lightbox-close:hover {
            color: #000;
        }
        
        .query-details h3 {
            margin-top: 0;
            color: #323130;
        }
        
        .query-details p {
            margin: 8px 0;
            font-size: 14px;
            line-height: 1.4;
        }
    </style>
    <script type="text/javascript">
        VSS.init({
            explicitNotifyLoaded: true,
            usePlatformStyles: true
        });

        VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/WorkItemTracking/RestClient"], 
            function (WidgetHelpers, WorkItemTrackingRestClient) {
                WidgetHelpers.IncludeWidgetStyles();
                
                function showQueryDetails(query) {
                    // Lightbox implementation from above
                }
                
                VSS.register("HelloWorldWidget2", function () {                
                    var projectId = VSS.getWebContext().project.id;

                    var getQueryInfo = function (widgetSettings) {
                        return WorkItemTrackingRestClient.getClient().getQuery(projectId, "Shared Queries/Feedback")
                            .then(function (query) {
                                // Enhanced display with lightbox trigger
                                var $list = $('<ul class="query-summary">');                                
                                $list.append($('<li>').text("Query ID: " + query.id));
                                $list.append($('<li>').text("Query Name: " + query.name));
                                $list.append($('<li>').text("Created By: " + (query.createdBy ? query.createdBy.displayName : "<unknown>")));

                                var $detailsLink = $('<button class="details-link">View Details</button>');
                                $detailsLink.on('click', function() {
                                    showQueryDetails(query);
                                });

                                var $container = $('#query-info-container');
                                $container.empty();
                                $container.append($list);
                                $container.append($detailsLink);

                                return WidgetHelpers.WidgetStatusHelper.Success();
                            }, function (error) {
                                return WidgetHelpers.WidgetStatusHelper.Failure(error.message);
                            });
                    }

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

                            return getQueryInfo(widgetSettings);
                        }
                    }
                });
            VSS.notifyLoadSucceeded();
        });       
    </script>
</head>
<body>
    <div class="widget">
        <h2 class="title"></h2>
        <div id="query-info-container"></div>
    </div>
</body>
</html>

Zagadnienia dotyczące ułatwień dostępu: Upewnij się, że lightbox jest dostępny za pomocą klawiatury i zawiera odpowiednie etykiety dla czytników zawartości ekranu. Testowanie za pomocą wbudowanych funkcji ułatwień dostępu usługi Azure DevOps.

Ważne

Wydajność: lightboxy powinny być ładowane szybko. Rozważ leniwe ładowanie szczegółowych danych tylko wtedy, gdy lightbox zostanie otwarty, zamiast pobierać wszystko z góry.

Krok 5. Konfigurowanie manifestu rozszerzenia

Zarejestruj zarówno konfigurowalny widżet, jak i jego interfejs konfiguracji w manifeście rozszerzenia.

Dodawanie widżetu i opcji konfiguracji

Aktualizacja vss-extension.json w celu uwzględnienia dwóch nowych składek:

{
    "contributions": [
        // ...existing 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
        }
    ]
}

Wymagania dotyczące wkładu w konfigurację

Własność Przeznaczenie Wymagana wartość
type Identyfikuje wkład jako konfigurację widżetu ms.vss-dashboards-web.widget-configuration
targets Gdzie jest wyświetlana konfiguracja ms.vss-dashboards-web.widget-configuration
uri Ścieżka do pliku HTML konfiguracji Ścieżka pliku konfiguracji

Wzorzec kierowania widżetu

W przypadku konfigurowalnych widżetów tablica targets musi zawierać odwołanie do konfiguracji:

<publisher>.<extension-id>.<configuration-id>

Ostrzeżenie

Widoczność przycisku konfiguracji: jeśli widżet nie jest prawidłowo ukierunkowany na jego wkład w konfigurację, przycisk Konfiguruj nie jest wyświetlany. Sprawdź, czy nazwy wydawcy i rozszerzeń są dokładnie zgodne z manifestem.

Krok 6. Pakowanie, publikowanie i udostępnianie

Wdróż rozszerzenie rozszerzone przy użyciu funkcji konfiguracji.

Jeśli jest to twoja pierwsza publikacja, wykonaj czynności opisane w kroku 6: Pakowanie, publikowanie i udostępnianie. W przypadku istniejących rozszerzeń przepakuj i zaktualizuj je bezpośrednio w witrynie Marketplace.

Krok 7. Testowanie konfigurowalnego widżetu

Poznaj pełny przepływ pracy konfiguracji, dodając i konfigurując widżet.

Dodawanie widżetu do pulpitu nawigacyjnego

  1. Przejdź do https://dev.azure.com/{Your_Organization}/{Your_Project}.
  2. Przejdź do sekcji Przegląd>Pulpity nawigacyjne.
  3. Wybierz Dodaj widżet.
  4. Znajdź pozycję "Hello World Widget 3 (z konfiguracją)" i wybierz pozycję Dodaj.

Zostanie wyświetlony monit o konfigurację, ponieważ widżet wymaga konfiguracji:

Zrzut ekranu przedstawiający pulpit nawigacyjny Przegląd z przykładowym widżetem z wykazu.

Konfigurowanie widżetu

Uzyskiwanie dostępu do konfiguracji za pomocą jednej z metod:

  • Menu widżetu: umieść kursor nad widżetem, wybierz wielokropek (⋯), a następnie Konfiguruj
  • Tryb edycji pulpitu nawigacyjnego: wybierz pozycję Edytuj na pulpicie nawigacyjnym, a następnie przycisk konfiguruj w widżecie

Panel konfiguracji otwiera się z podglądem na żywo w centrum. Wybierz zapytanie z listy rozwijanej, aby wyświetlić natychmiastowe aktualizacje, a następnie wybierz pozycję Zapisz , aby zastosować zmiany.

Krok 8. Dodawanie zaawansowanych opcji konfiguracji

Rozszerz widżet przy użyciu bardziej wbudowanych funkcji konfiguracji, takich jak nazwy niestandardowe i rozmiary.

Włącz opcję konfiguracji nazwy i rozmiaru

Usługa Azure DevOps udostępnia dwie konfigurowalne funkcje gotowe do użycia:

Funkcja Właściwość manifestu Przeznaczenie
Nazwy niestandardowe isNameConfigurable: true Użytkownicy mogą zastąpić domyślną nazwę widżetu
Wiele rozmiarów Wiele supportedSizes wpisów Użytkownicy mogą zmieniać rozmiar widżetów

Przykład rozszerzonego manifestu

{
    "contributions": [
        {
             "id": "HelloWorldWidget3",
             "type": "ms.vss-dashboards-web.widget",
             "targets": [
                 "ms.vss-dashboards-web.widget-catalog",  
                 "fabrikam.azuredevops-extensions-myExtensions.HelloWorldWidget.Configuration"
             ],
             "properties": {
                 "name": "Hello World Widget 3 (with config)",
                 "description": "My third widget",
                 "previewImageUrl": "img/preview3.png",                       
                 "uri": "hello-world3.html",
                 "isNameConfigurable": true,
                 "supportedSizes": [
                    {
                        "rowSpan": 1,
                        "columnSpan": 2
                    },
                    {
                        "rowSpan": 2,
                        "columnSpan": 2
                    }
                 ],
                 "supportedScopes": ["project_team"]
             }
         }
    ]
}

Wyświetlane skonfigurowane nazwy

Aby wyświetlić niestandardowe nazwy widżetów, zaktualizuj widżet, aby używał polecenia widgetSettings.name:

return {
    load: function (widgetSettings) {
        // Display configured name instead of hard-coded text
        var $title = $('h2.title');
        $title.text(widgetSettings.name);

        return getQueryInfo(widgetSettings);
    },
    reload: function (widgetSettings) {
        // Update name during configuration changes
        var $title = $('h2.title');
        $title.text(widgetSettings.name);

        return getQueryInfo(widgetSettings);
    }
}

Po zaktualizowaniu rozszerzenia można skonfigurować zarówno nazwę widżetu, jak i rozmiar:

Zrzut ekranu przedstawiający, gdzie można skonfigurować nazwę i rozmiar widżetu.

Przepakuj i zaktualizuj rozszerzenie, aby włączyć te zaawansowane opcje konfiguracji.

Gratulacje! Utworzono kompletny, konfigurowalny widżet pulpitu nawigacyjnego usługi Azure DevOps z funkcjami podglądu na żywo i opcjami dostosowywania użytkownika.