Добавление мини-приложения панели мониторинга

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

Мини-приложения на панели мониторинга реализуются в виде вкладов в платформу расширений. Одно расширение может иметь несколько вкладов. Узнайте, как создать расширение с несколькими мини-приложениями в качестве вкладов.

Эта статья разделена на три части, каждая сборка предыдущего — начиная с простого мини-приложения и заканчивая комплексным мини-приложением.

Совет

Ознакомьтесь с нашей новой документацией по разработке расширений с помощью пакета SDK для расширений Azure DevOps.

Подготовка и требуемая настройка для этого руководства

Чтобы создать расширения для Azure DevOps или TFS, вам потребуется следующее:

Знание. Некоторые знания о JavaScript, HTML, CSS требуются для разработки мини-приложений.

  • Организация в Azure DevOps для установки и тестирования мини-приложения, дополнительные сведения см. здесь.
  • Текстовый редактор. Для многих учебников мы использовали Visual Studio Code, которые можно скачать здесь.
  • Последняя версия узла, которую можно скачать здесь
  • Кроссплатформенный интерфейс командной строки для Azure DevOps (tfx-cli) для упаковки расширений.
    • tfx-cli можно установить с помощью npmкомпонента Node.js, выполнив команду npm i -g tfx-cli
  • Домашний каталог для проекта. Этот каталог называется home на протяжении всего учебника.

Структура файла расширения:

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

Что вы найдете в руководстве

  1. В первой части этого руководства показано, как создать новое мини-приложение, которое выводит простое сообщение Hello World.
  2. Вторая часть основана на первой, добавив вызов к REST API Azure DevOps.
  3. В третьей части объясняется, как добавить конфигурацию в мини-приложение.

Примечание.

Если вы спешите и хотите получить руки на код сразу же, вы можете скачать примеры здесь. После скачивания перейдите в widgets папку, а затем следуйте шагу 6 и шагу 7 непосредственно, чтобы опубликовать пример расширения, в котором три примера мини-приложений различных сложностей.

Начало работы с некоторыми основными стилями мини-приложений , которые мы предоставляем из поля для вас и некоторые рекомендации по структуре мини-приложений.

Часть 1. Hello World

В этой части представлен мини-приложение, которое печатает "Hello World" с помощью JavaScript.

Overview dashboard with a sample widget

Шаг 1. Получение клиентского пакета SDK — VSS.SDK.min.js

Основной скрипт VSS.SDK.min.jsПАКЕТА SDK позволяет веб-расширениям взаимодействовать с узлом кадром Azure DevOps. Скрипт выполняет такие операции, как инициализация, загрузка расширения уведомления или получение контекста текущей страницы. Получите файл пакета SDK VSS.SDK.min.js клиента и добавьте его в веб-приложение. Поместите его в папку home/sdk/scripts .

Используйте команду npm install, чтобы получить пакет SDK:

npm install vss-web-extension-sdk

Дополнительные сведения о пакете SDK см. на странице GitHub клиентского пакета SDK.

Шаг 2. Html-страница — hello-world.html

Html-страница — это клей, который содержит макет вместе и содержит ссылки на CSS и JavaScript. Вы можете присвоить этому файлу любое имя, просто обязательно обновите все ссылки на hello-world имя, используемое вами.

Мини-приложение основано на HTML и размещается в iframe. Добавьте приведенный ниже HTML-код в hello-world.html. Мы добавим обязательную ссылку на VSS.SDK.min.js файл и добавим h2 в него элемент, который обновляется строкой Hello World в предстоящем шаге.

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

Несмотря на то что мы используем HTML-файл, большинство элементов головки HTML, отличных от скрипта и ссылки, игнорируются платформой.

Шаг 3. JavaScript

Мы используем JavaScript для отображения содержимого в мини-приложении. В этой статье мы упаковаем весь код JavaScript внутри &lt;script&gt; элемента в HTML-файле. Этот код можно выбрать в отдельном файле JavaScript и ссылаться на него в HTML-файле. Код отрисовывает содержимое. Этот код JavaScript также инициализирует пакет SDK VSS, сопоставляет код мини-приложения с именем мини-приложения и уведомляет платформу расширений об успешном выполнении или сбоях мини-приложения. В нашем случае ниже приведен код, который будет печатать "Hello World" в мини-приложении. Добавьте этот script элемент в 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 инициализирует подтверждение между iframe, в котором размещен мини-приложение и кадр узла. Мы передаем explicitNotifyLoaded: true , чтобы мини-приложение было явно уведомлять узел о завершении загрузки. Этот элемент управления позволяет уведомлять о завершении загрузки после того, как будут загружены зависимые модули. Мы передаем usePlatformStyles: true , чтобы основные стили Azure DevOps для html-элементов (например, body, div и т. д.) можно использовать мини-приложением. Если мини-приложение предпочитает не использовать эти стили, они могут передаваться usePlatformStyles: false.

VSS.require используется для загрузки необходимых библиотек скриптов VSS. Вызов этого метода автоматически загружает общие библиотеки, такие как JQuery и JQueryUI. В нашем случае мы зависят от библиотеки WidgetHelpers, которая используется для обмена данными о состоянии мини-приложения с платформой мини-приложений. Таким образом, мы передаем соответствующее имя TFS/Dashboards/WidgetHelpers модуля и обратный VSS.requireвызов. Обратный вызов вызывается после загрузки модуля. Обратный вызов содержит остальную часть кода JavaScript, необходимого для мини-приложения. В конце обратного вызова мы вызываем VSS.notifyLoadSucceeded уведомление о завершении загрузки.

WidgetHelpers.IncludeWidgetStyles содержит таблицу стилей с некоторыми базовыми css для начала работы. Не забудьте упаковать содержимое внутри HTML-элемента с классом widget , чтобы использовать эти стили.

VSS.register используется для сопоставления функции в JavaScript, которая однозначно определяет мини-приложение среди различных вкладов в расширение. Имя должно совпадать id с именем, определяющим ваш вклад, как описано на шаге 5. Для мини-приложений функция, передаваемая для VSS.register возврата объекта, удовлетворяющего IWidget контракту, например, возвращаемый объект должен иметь свойство load, значение которого является другой функцией, которая имеет основную логику для отрисовки мини-приложения. В нашем случае это обновление текста h2 элемента на Hello World. Это эта функция, которая вызывается, когда платформа мини-приложений создает экземпляр мини-приложения. Мы используем WidgetStatusHelper приложение WidgetHelpers для возврата в качестве успешного WidgetStatus .

Предупреждение

Если имя, используемое для регистрации мини-приложения, не соответствует идентификатору для вклада в манифест, то мини-приложение будет неожиданно работать.

Всегда vss-extension.json должен находиться в корне папки (в этом руководстве). HelloWorld Для всех остальных файлов их можно поместить в любую структуру в папке, просто обновите ссылки соответствующим образом в HTML-файлах и манифесте vss-extension.json .

Шаг 4. Логотип расширения: logo.png

Логотип отображается в Marketplace и в каталоге мини-приложений после установки расширения.

Вам нужен значок каталога 98 пикселей x 98-px. Выберите изображение, назовите его logo.pngи поместите его в папку img .

Для поддержки TFS 2015 с обновлением 3 требуется дополнительный образ, который составляет 330 пикселей x 160 пикселей. Этот образ предварительного просмотра показан в этом каталоге. Выберите изображение, назовите его preview.pngи поместите его в папку img , как и раньше.

Вы можете присвоить этим изображениям имя, если манифест расширения на следующем шаге обновляется с именами, которые вы используете.

Шаг 5. Манифест расширения: vss-extension.json

Создайте json-файл (vss-extension.jsonнапример, в каталоге home со следующим содержимым):

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

Дополнительные сведения о обязательных атрибутах см. в справочнике по манифесту расширения

Примечание.

Здесь нужно изменить издателя на имя издателя. Чтобы создать издателя, перейдите к разделу Package/Publish/Install.

Значки

Значки стэнза указывают путь к значку расширения в манифесте.

Участие в проекте

Каждая запись вклада определяет свойства.

  • Идентификатор для идентификации вашего вклада. Этот идентификатор должен быть уникальным в пределах расширения. Этот идентификатор должен совпадать с именем, используемым на шаге 3 для регистрации мини-приложения.
  • Тип вклада. Для всех мини-приложений тип должен быть ms.vss-dashboards-web.widget.
  • Массив целевых объектов , в которые вносится вклад. Для всех мини-приложений целевой объект должен быть [ms.vss-dashboards-web.widget-catalog].
  • Свойства — это объекты, включающие свойства для типа вклада. Для мини-приложений обязательны следующие свойства.
Свойство Описание
name Имя мини-приложения, отображаемое в каталоге мини-приложений.
description Описание мини-приложения, отображаемого в каталоге мини-приложений.
catalogIconUrl Относительный путь к значку каталога, добавленного на шаге 4 для отображения в каталоге мини-приложений. Изображение должно быть 98 пикселей x 98 пикселей. Если вы использовали другую структуру папок или другое имя файла, укажите соответствующий относительный путь здесь.
previewImageUrl Относительный путь к изображению предварительного просмотра, добавленного на шаге 4 , для отображения только в каталоге мини-приложений для TFS 2015 с обновлением 3. Изображение должно быть 330 пикселей x 160 пикселей. Если вы использовали другую структуру папок или другое имя файла, укажите соответствующий относительный путь здесь.
uri Относительный путь к HTML-файлу, добавленного на шаге 1. Если вы использовали другую структуру папок или другое имя файла, укажите соответствующий относительный путь здесь.
поддерживаемыеSizes Массив размеров, поддерживаемых мини-приложением. Если мини-приложение поддерживает несколько размеров, первый размер в массиве — это размер мини-приложения по умолчанию. Указан widget size для строк и столбцов, занятых мини-приложением в сетке панели мониторинга. Одна строка или столбец соответствует 160 пикселей. Любое измерение выше 1x1 получает дополнительные 10 пикселей, которые представляют забор между мини-приложениями. Например, мини-приложение 3x2 имеет ширину 160*3+10*2 и 160*2+10*1 высоту. Максимальный поддерживаемый размер 4x4.
поддерживаемыеScopes На данный момент мы поддерживаем только панели мониторинга группы. Значение должно быть project_team. В будущем, когда мы поддерживаем другие область панели мониторинга, здесь будут доступны дополнительные варианты.

Files

Файлы стэнза содержат файлы, которые необходимо включить в пакет — HTML-страницу, скрипты, скрипты пакета SDK и логотип. Установите значение addressabletrue , если вы не включаете другие файлы, которые не должны быть url-адресируемыми.

Примечание.

Дополнительные сведения о файле манифеста расширения, например его свойствах и возможностях, проверка ссылку на манифест расширения.

Шаг 6. Упаковка, публикация и общий доступ

После написания расширения следующий шаг к его получению в Marketplace заключается в том, чтобы упаковать все файлы вместе. Все расширения упаковываются в виде совместимых vsix-файлов VSIX 2.0. Корпорация Майкрософт предоставляет кроссплатформенный интерфейс командной строки (CLI) для упаковки расширения.

Получение средства упаковки

Вы можете установить или обновить кроссплатформенный интерфейс командной строки для Azure DevOps (tfx-cli) с помощью npmкомпонента Node.js из командной строки.

npm i -g tfx-cli

Упаковка расширения

Упаковка расширения в VSIX-файл без усилий после того, как у вас есть tfx-cli. Перейдите в домашний каталог расширения и выполните следующую команду.

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

Примечание.

При каждом обновлении необходимо увеличить версию расширения или интеграции.
При обновлении существующего расширения обновите версию манифеста или передайте переключатель командной --rev-version строки. Это увеличивает номер версии исправления расширения и сохраняет новую версию в манифесте.

После создания упаковаемого расширения в VSIX-файле вы будете готовы опубликовать расширение в Marketplace.

Создание издателя для расширения

Все расширения, включая расширения от Корпорации Майкрософт, определяются как предоставляемые издателем. Если вы еще не являетесь членом существующего издателя, создайте его.

  1. Вход на портал публикации Visual Studio Marketplace
  2. Если вы еще не являетесь членом существующего издателя, вам будет предложено создать издателя. Если вам не предлагается создать издателя, прокрутите вниз до нижней части страницы и выберите "Опубликовать расширения" под связанными сайтами.
    • Укажите идентификатор издателя, например: mycompany-myteam
      • Идентификатор используется в качестве значения атрибута publisher в файле манифеста расширений.
    • Укажите отображаемое имя издателя, например: My Team
  3. Просмотрите соглашение издателя Marketplace и нажмите кнопку "Создать"

Теперь издатель определен. В будущем выпуске можно предоставить разрешения для просмотра расширений издателя и управления ими. Это легко и безопасно для команд и организаций публиковать расширения под общим издателем, но без необходимости предоставлять общий доступ к набору учетных данных в наборе пользователей.

Обновите файл манифеста в примерах, чтобы заменить фиктивный vss-extension.json идентификатор fabrikam издателя идентификатором издателя.

Публикация и предоставление общего доступа к расширению

После создания издателя теперь можно отправить расширение в Marketplace.

  1. Найдите кнопку "Отправить новое расширение", перейдите к упаковаированному VSIX-файлу и выберите команду "Отправить".

Вы также можете отправить расширение через командную строку с помощью tfx extension publish команды, а не tfx extension create для упаковки и публикации расширения на одном шаге. Вы также можете использовать --share-with для совместного использования расширения с одной или несколькими учетными записями после публикации. Вам также потребуется личный маркер доступа.

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

Шаг 7. Добавление мини-приложения из каталога

  1. Перейдите к проекту в Azure DevOps, http://dev.azure.com/{yourOrganization}/{yourProject}

  2. Выберите "Обзор" и выберите панели мониторинга.

  3. Нажмите кнопку "Добавить мини-приложение".

  4. Выделите мини-приложение и нажмите кнопку "Добавить".

    Мини-приложение отображается на панели мониторинга.

Часть 2. Hello World с REST API Azure DevOps

Мини-приложения могут вызывать любой из интерфейсов REST API в Azure DevOps для взаимодействия с ресурсами Azure DevOps. В этом примере мы используем REST API для WorkItemTracking для получения сведений о существующем запросе и отображения некоторых сведений о запросе в мини-приложении прямо под текстом Hello World.

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

Шаг 1. HTML

Скопируйте файл hello-world.html из предыдущего примера и переименуйте копию hello-world2.htmlв . Теперь папка выглядит следующим образом:

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

Добавьте новый элемент div прямо под элементом h2 для хранения сведений о запросе. Обновите имя мини-приложения из HelloWorldWidget до HelloWorldWidget2 в строке, в которой вы вызываете VSS.register. Это позволяет платформе однозначно идентифицировать мини-приложение в расширении.
<!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>

Шаг 2. Доступ к ресурсам Azure DevOps

Чтобы включить доступ к ресурсам Azure DevOps, область необходимо указать в манифесте расширения. Мы добавим vso.work в манифест область.
Это область указывает, что мини-приложение нуждается в доступе только для чтения к запросам и рабочим элементам. Ознакомьтесь со всеми доступными область здесь. Добавьте приведенные ниже сведения в конце манифеста расширения.

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

Предупреждение

Добавление или изменение область после публикации расширения в настоящее время не поддерживается. Если вы уже загрузили расширение, удалите его из Marketplace. Visual Studio Marketplace Publishing PortalПерейдите по ссылке, щелкните правой кнопкой мыши расширение и нажмите кнопку "Удалить".

Шаг 3. Вызов REST API

Существует множество клиентских библиотек, к которым можно получить доступ через пакет SDK для выполнения вызовов REST API в Azure DevOps. Эти библиотеки называются клиентами REST и являются оболочками JavaScript вокруг вызовов Ajax для всех доступных конечных точек на стороне сервера. Вы можете использовать методы, предоставляемые этими клиентами, вместо написания вызовов Ajax самостоятельно. Эти методы сопоставляют ответы API с объектами, которые можно использовать в коде.

На этом шаге VSS.require мы обновим вызов загрузки TFS/WorkItemTracking/RestClient, который предоставляет клиент REST WorkItemTracking. Этот клиент REST можно использовать для получения сведений о запросе, вызываемом Feedback в папке Shared Queries.

Внутри передаваемой VSS.registerфункции мы создадим переменную для хранения текущего идентификатора проекта. Нам нужна эта переменная, чтобы получить запрос. Мы также создадим новый метод getQueryInfo для использования клиента REST. Этот метод, который затем вызывается из метода load.

Этот метод getClient предоставляет экземпляр необходимого клиента REST. Метод getQuery возвращает запрос, упакованный в обещание. Обновленная версия VSS.require выглядит следующим образом:

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

Обратите внимание на использование метода Failure из WidgetStatusHelper. Он позволяет указать платформу мини-приложений, что произошла ошибка и воспользоваться стандартным интерфейсом ошибок, предоставляемым всем мини-приложениям.

Если у вас нет Feedback запроса в Shared Queries папке, замените Shared Queries\Feedback код путем запроса, существующего в проекте.

Шаг 4. Отображение ответа

Последний шаг — отрисовка сведений запроса внутри мини-приложения. Функция getQuery возвращает объект типа Contracts.QueryHierarchyItem внутри обещания. В этом примере отображается идентификатор запроса, имя запроса и имя создателя запроса в текстовом тексте Hello World. Замените // Do something with the 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);

Ваш финал hello-world2.html выглядит следующим образом:

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

Шаг 5. Манифест расширения Обновления

На этом шаге мы обновим манифест расширения, чтобы включить запись для второго мини-приложения. Добавьте новый вклад в массив в contributions свойстве и добавьте новый файл hello-world2.html в массив в свойстве файлов. Для второго мини-приложения требуется еще один предварительный просмотр. Назовите его preview2.png и поместите его в папку img .

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

Шаг 6. Упаковка, публикация и общий доступ

Упаковка, публикация и предоставление общего доступа к расширению. Если вы уже опубликовали расширение, вы можете перепаковать расширение и напрямую обновить его в Marketplace.

Шаг 7. Добавление мини-приложения из каталога

Теперь перейдите на панель мониторинга https:\//dev.azure.com/{yourOrganization}/{yourProject}команды. Если эта страница уже открыта, обновите ее. Наведите указатель мыши на кнопку "Изменить" в правом нижнем углу и нажмите кнопку "Добавить". Откроется каталог мини-приложений, где вы нашли установленное мини-приложение. Выберите мини-приложение и нажмите кнопку "Добавить", чтобы добавить ее на панель мониторинга.

Часть 3. Hello World с конфигурацией

В части 2 этого руководства вы узнали, как создать мини-приложение, отображающее сведения о запросах для жестко закодированного запроса. В этой части мы добавим возможность настроить запрос, который будет использоваться вместо жестко закодированного. При использовании режима конфигурации пользователь получает просмотр динамического предварительного просмотра мини-приложения на основе их изменений. Эти изменения сохраняются в мини-приложении на панели мониторинга при нажатии кнопки "Сохранить".

Overview dashboard live preview of the widget based on changes.

Шаг 1. HTML

Реализация конфигураций мини-приложений и мини-приложений очень похожа. Оба реализованы в платформе расширений в качестве вкладов. Оба используют один и тот же файл ПАКЕТА SDK. VSS.SDK.min.js Оба они основаны на HTML, JavaScript и CSS.

Скопируйте файл html-world2.html из предыдущего примера и переименуйте копию hello-world3.htmlв . Добавьте другой HTML-файл с именем configuration.html. Теперь папка выглядит следующим образом:

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

Добавьте приведенный ниже HTML-код в configuration.html. Мы в основном добавим обязательную ссылку на VSS. Файл SDK.min.js и элемент select для раскрывающегося списка, чтобы выбрать запрос из предустановленного списка.
    <!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>

Шаг 2. JavaScript — конфигурация

Используйте JavaScript для отображения содержимого в конфигурации мини-приложения так же, как и для мини-приложения на шаге 3 части 1 в этом руководстве. Этот код JavaScript отображает содержимое, инициализирует пакет SDK VSS, сопоставляет код конфигурации мини-приложения с именем конфигурации и передает параметры конфигурации в платформу. В нашем случае ниже приведен код, который загружает конфигурацию мини-приложения. Откройте файл configuration.html и приведенный ниже <script> элемент <head>.

    <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.requireи играть ту же роль, что и VSS.register для мини-приложения, как описано в части 1. Единственное различие заключается в том, что для конфигураций мини-приложений функция, передаваемая для VSS.register возврата объекта, удовлетворяющего контракту IWidgetConfiguration .

Свойство loadIWidgetConfiguration контракта должно иметь функцию в качестве значения. Эта функция содержит набор шагов для отрисовки конфигурации мини-приложения. В нашем случае необходимо обновить выбранное значение раскрывающегося элемента с существующими параметрами, если таковые имеются. Эта функция вызывается при создании экземпляра платформы widget configuration

Свойство onSaveIWidgetConfiguration контракта должно иметь функцию в качестве значения. Эта функция вызывается платформой, когда пользователь выбирает "Сохранить " в области конфигурации. Если входные данные пользователя готовы к сохранению, сериализируйте его в строку, создайте custom settings объект и сохраните WidgetConfigurationSave.Valid() входные данные пользователя.

В этом руководстве мы используем JSON для сериализации входных данных пользователя в строку. Вы можете выбрать любой другой способ сериализации входных данных пользователя в строку. Он доступен для мини-приложения с помощью настраиваемого WidgetSettings свойства Параметры объекта. Мини-приложение требует десериализации этого, который рассматривается на шаге 4.

Шаг 3. JavaScript— включение динамической предварительной версии

Чтобы включить динамическое обновление предварительной версии при выборе запроса из раскрывающегося списка, мы присоединяем обработчик событий изменения к кнопке. Этот обработчик уведомляет платформу о том, что конфигурация изменилась. Он также передает используемый customSettings для обновления предварительной версии. Чтобы уведомить платформу, notify метод необходимо widgetConfigurationContext вызвать. Он принимает два параметра, имя события, которое в данном случае — WidgetHelpers.WidgetEvent.ConfigurationChangeи EventArgs объект для события, созданного с customSettings помощью вспомогательного WidgetEvent.Args метода.

Добавьте приведенный ниже элемент в функцию, назначенную свойству load .

 $queryDropdown.on("change", function () {
     var customSettings = {
        data: JSON.stringify({
                queryPath: $queryDropdown.val()
            })
     };
     var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
     var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
     widgetConfigurationContext.notify(eventName, eventArgs);
 });

Необходимо уведомить платформу изменения конфигурации по крайней мере один раз, чтобы включить кнопку "Сохранить".

В конце 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>

Шаг 4. JavaScript — реализация перезагрузки в мини-приложении

Мы настроили конфигурацию мини-приложения для хранения пути запроса, выбранного пользователем. Теперь необходимо обновить код в мини-приложении, чтобы использовать эту хранимую конфигурацию вместо жестко закодированного Shared Queries/Feedback из предыдущего примера.

Откройте файл hello-world3.html и обновите имя мини-приложения в HelloWorldWidget2HelloWorldWidget3 строку, в которой вы вызываете VSS.register. Это позволяет платформе однозначно идентифицировать мини-приложение в расширении.

Функция, сопоставленная с HelloWorldWidget3 текущей VSS.register , возвращает объект, удовлетворяющий контракту IWidget . Так как наше мини-приложение теперь нуждается в настройке, эта функция должна быть обновлена, чтобы вернуть объект, удовлетворяющий контракту IConfigurableWidget . Для этого обновите инструкцию return, чтобы включить свойство, которое называется перезагрузкой, как показано ниже. Значение этого свойства — это функция, которая вызывает getQueryInfo метод еще раз. Этот метод перезагрузки вызывается платформой каждый раз, когда пользователь изменяет входные данные для отображения динамической предварительной версии. Это также вызывается при сохранении конфигурации.

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

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

Путь к жестко закодированному запросу в getQueryInfo должен быть заменен настроенным путем запроса, который можно извлечь из параметра "мини-приложение Параметры", который передается методу. Добавьте приведенный ниже текст в самом начале метода getQueryInfo и замените жестко закодированный путь запроса на 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();
}

На этом этапе мини-приложение готово к отображению с настроенными параметрами.

loadreload Оба свойства имеют аналогичную функцию. Это касается большинства простых мини-приложений. Для сложных мини-приложений будут выполняться определенные операции, которые нужно выполнять только один раз, независимо от того, сколько раз изменяется конфигурация. Или могут быть некоторые операции с большим весом, которые не должны выполняться более одного раза. Такие операции будут частью функции, соответствующей load свойству, а не свойству reload .

Шаг 5. Манифест расширения Обновления

vss-extension.json Откройте файл, чтобы включить две новые записи в массив в contributions свойство. Один для HelloWorldWidget3 мини-приложения и другой для его конфигурации. Вам нужен еще один предварительный просмотр образа для третьего мини-приложения. Назовите его preview3.png и поместите его в папку img . Обновите массив в свойстве files , чтобы включить два новых HTML-файла, которые мы добавили в этом примере.

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

Обратите внимание, что вклад в конфигурацию мини-приложений следует немного отличается от модели самого мини-приложения. Запись вклада для конфигурации мини-приложения имеет:
  • Идентификатор для идентификации вашего вклада. Это должно быть уникальным в пределах расширения.
  • Тип вклада. Для всех конфигураций мини-приложений это должно быть ms.vss-dashboards-web.widget-configuration
  • Массив целевых объектов , в которые вносится вклад. Для всех конфигураций мини-приложений это имеет одну запись: ms.vss-dashboards-web.widget-configuration
  • Свойства, содержащие набор свойств, включающих имя, описание и URI HTML-файла, используемого для настройки.

Для поддержки конфигурации необходимо также изменить вклад мини-приложения. Массив целевых объектов для мини-приложения необходимо обновить, чтобы включить идентификатор конфигурации в форму <publisher>.>id for the extension<,<id for the configuration contribution> что в данном случае .fabrikam.vsts-extensions-myExtensions.HelloWorldWidget.Configuration

Предупреждение

Если запись вклада для настраиваемого мини-приложения не нацелена на конфигурацию с использованием правильного издателя и имени расширения, как описано ранее, кнопка настройки не отображается для мини-приложения.

В конце этой части файл манифеста должен содержать три мини-приложения и одну конфигурацию. Полный манифест можно получить из примера здесь.

Шаг 6. Упаковка, публикация и общий доступ

Если вы еще не опубликовали расширение, ознакомьтесь с этим разделом , чтобы упаковать, опубликовать и предоставить общий доступ к расширению. Если вы уже опубликовали расширение до этого момента, вы можете переупаковать расширение и напрямую обновить его в Marketplace.

Шаг 7. Добавление мини-приложения из каталога

Теперь перейдите на панель мониторинга группы в https://dev.azure.com/{yourOrganization}/{yourProject}. Если эта страница уже открыта, обновите ее. Наведите указатель мыши на кнопку "Изменить" в правом нижнем углу и нажмите кнопку "Добавить". Откроется каталог мини-приложений, в котором вы нашли установленное мини-приложение. Выберите мини-приложение и нажмите кнопку "Добавить", чтобы добавить ее на панель мониторинга.

Появится сообщение с просьбой настроить мини-приложение.

Overview dashboard with a sample widget from the catalog.

Существует два способа настройки мини-приложений. Один из них — навести указатель мыши на мини-приложение, выбрать многоточие, которое отображается в правом верхнем углу, а затем нажмите кнопку "Настроить". Другой — выбрать кнопку "Изменить" в правом нижнем углу панели мониторинга, а затем нажать кнопку настройки, которая отображается в правом верхнем углу мини-приложения. Откроется интерфейс конфигурации справа и предварительная версия мини-приложения в центре. Перейдите к запросу в раскрывающемся списке. В динамической предварительной версии отображаются обновленные результаты. Выберите "Сохранить" и мини-приложение отображает обновленные результаты.

Шаг 8. Настройка дополнительных (необязательных)

Вы можете добавить столько элементов формы HTML, сколько требуется в configuration.html дополнительной конфигурации. Существует две настраиваемые функции, доступные из поля: имя мини-приложения и размер мини-приложения.

По умолчанию имя, указанное для мини-приложения в манифесте расширения, хранится в качестве имени мини-приложения для каждого экземпляра мини-приложения, который когда-либо добавляется на панель мониторинга. Вы можете разрешить пользователям настраивать это, чтобы они могли добавить любое имя, которое они хотят, в свой экземпляр мини-приложения. Чтобы разрешить такую конфигурацию, добавьте isNameConfigurable:true в раздел свойств мини-приложения в манифесте расширения.

Если вы предоставляете несколько записей для мини-приложения в массиве supportedSizes в манифесте расширения, пользователи также могут настроить размер мини-приложения.

Манифест расширения для третьего примера в этом руководстве будет выглядеть следующим образом, если включить конфигурацию имени мини-приложения и размера:

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

При предыдущем изменении перепакуйте и обновите расширение. Обновите панель мониторинга с этим мини-приложением (Hello World Widget 3 (с конфигурацией)). Откройте режим конфигурации для мини-приложения, теперь вы сможете просмотреть параметр для изменения имени и размера мини-приложения.

Widget where name and size can be configured

Перейдите вперед и выберите другой размер в раскрывающемся списке. Отображается изменение размера динамического предварительного просмотра. Сохраните изменения и мини-приложение на панели мониторинга также изменяется.

Предупреждение

Если вы удалили уже поддерживаемый размер, мини-приложение не загружается должным образом. Мы работаем над исправлением для будущего выпуска.

Изменение имени мини-приложения не приводит к каким-либо видимым изменениям в мини-приложении. Это связано с тем, что наши примеры мини-приложений не отображают имя мини-приложения в любом месте. Давайте изменим пример кода, чтобы отобразить имя мини-приложения вместо жестко закодированного текста Hello World.

Для этого замените жестко закодированный текст Hello World widgetSettings.name на строку, в которой мы задали текст h2 элемента. Это гарантирует, что имя мини-приложения отображается каждый раз, когда мини-приложение загружается на обновление страницы. Так как мы хотим, чтобы динамический просмотр обновлялся каждый раз при изменении конфигурации, мы должны добавить тот же код в reload часть нашего кода. Последняя инструкция hello-world3.html возврата приведена следующим образом:

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

Перепакуйте и обновите расширение еще раз. Обновите панель мониторинга с этим мини-приложением. Все изменения имени мини-приложения в режиме конфигурации теперь обновите название мини-приложения.