Aracılığıyla paylaş


Gösterge tablosu bileşeni ekle

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

Bir panodaki pencere öğeleri, katkı olarak uzantı çerçevesinde uygulanır. Tek bir uzantının birden çok katkısı olabilir. Birden çok pencere öğesini katkı olarak içeren bir uzantı yapmayı öğrenin.

Bu makale, her biri öncekine dayanarak üç bölüme ayrılmıştır. Basit bir pencere öğesiyle başlar ve kapsamlı bir pencere öğesiyle bitersiniz.

İpucu

En yeni uzantı geliştirme belgelerimize göz atın, Azure DevOps Uzantı SDK'sını kullanarak.

Önkoşullar

Gereksinim Açıklama
Programlama bilgisi Pencere öğesi geliştirme için JavaScript, HTML ve CSS bilgisi
Azure DevOps kuruluşu Kuruluş oluşturma
Metin düzenleyicisi Öğreticiler için Visual Studio Code kullanıyoruz
Node.js Node.js'in en son sürümü
Platformlar arası CLI tfx-cli uzantıları paketlemek için
Şu şekilde yükleyin: npm i -g tfx-cli
Proje dizini Öğreticiyi tamamladıktan sonra bu yapıya sahip ana dizin:

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

Öğreticiye genel bakış

Bu öğretici, üç aşamalı örnekle pencere öğesi geliştirmeyi öğretir:

Bölüm Odak Öğrendikleriniz
Bölüm 1: Merhaba Dünya Temel widget oluşturma Metin görüntüleyen bir pencere öğesi oluşturma
Bölüm 2: REST API tümleştirmesi Azure DevOps API çağrıları Verileri getirmek ve görüntülemek için REST API işlevselliği ekleme
Bölüm 3: Pencere öğesi yapılandırması Kullanıcı özelleştirmesi Pencere öğeniz için yapılandırma seçeneklerini uygulayın

İpucu

Öğreticiyi atlayın: Örnek uzantının tamamını indirin, klasöre widgets gidin ve 6. Adım'a atlayarak üç kullanıma hazır örnek pencere öğesi yayımlayın.

Başlamadan önce, sağladığımız temel pencere öğesi stillerini ve yapısal yönergeleri gözden geçirin.

Bölüm 1: Merhaba Dünya

JavaScript kullanarak "Merhaba Dünya" ifadesini görüntüleyen temel bir pencere öğesi oluşturun. Bu temeller, pencere öğesi geliştirmedeki temel kavramları gösterir.

Örnek pencere öğesi içeren Genel Bakış panosunun ekran görüntüsü.

1. Adım: İstemci SDK'sını yükleme

VSS SDK, widget'ınızın Azure DevOps ile iletişim kurmasını sağlar. npm kullanarak yükleyin:

npm install vss-web-extension-sdk

VSS.SDK.min.js dosyasını vss-web-extension-sdk/lib içinden home/sdk/scripts klasörünüze kopyalayın.

Daha fazla SDK belgesi için İstemci SDK GitHub sayfasına bakın.

2. Adım: HTML yapısını oluşturma

Proje dizininizde oluşturun hello-world.html . Bu dosya, pencere öğesinin düzenini ve gerekli betiklere referansları sağlar.

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

Pencere öğeleri iframe'lerde çalıştırıldığından, <script> ve <link> hariç çoğu HTML baş öğesi framework tarafından yok sayılır.

3. Adım: JavaScript pencere öğesi ekleme

Pencere öğesi işlevini uygulamak için bu betiği <head> HTML dosyanızın bölümüne ekleyin:

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

Önemli JavaScript bileşenleri

İşlev Amaç
VSS.init() Pencere öğesi ile Azure DevOps arasındaki iletişimi başlatır
VSS.require() Gerekli SDK kitaplıklarını ve pencere öğesi yardımcılarını yükler
VSS.register() Pencere öğesinizi benzersiz bir tanımlayıcıyla kaydeder
WidgetHelpers.IncludeWidgetStyles() Varsayılan Azure DevOps stili uygular
VSS.notifyLoadSucceeded() Yüklemenin başarıyla tamamlandığını framework'e bildirir

Önemli

VSS.register() içindeki pencere öğesi adı, uzantı manifestinizdeki id ile eşleşmelidir (5. Adım).

4. Adım: Uzantı görüntüleri ekleme

Uzantınız için gerekli görüntüleri oluşturun:

  • Uzantı logosu: img klasöründe logo.png adlı, 98x98 piksel bir resim
  • Pencere öğesi kataloğu simgesi: img klasöründe, CatalogIcon.png adıyla 98x98 piksel görüntü.
  • Pencere öğesi önizlemesi: img klasöründe preview.png adlı 330x160 piksel görüntü

Bu görüntüler, kullanıcılar kullanılabilir uzantılara göz atarken Market ve pencere öğesi kataloğunda görüntülenir.

5. Adım: Uzantı bildirimini oluşturma

Projenizin kök dizininde oluşturun vss-extension.json . Bu dosya, uzantınızın meta verilerini ve katkılarını tanımlar:

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

Önemli

Gerçek yayımcı adınızla değiştirmek için "publisher": "fabrikam" ifadesini kullanın. Yayımcı oluşturmayı öğrenin.

Temel bildirim özellikleri

Bölüm Amaç
Temel bilgiler Uzantı adı, sürümü, açıklaması ve yayımcısı
Simgeler Eklentinizin görsel öğelerinin yolları
Katkı Kimlik, tür ve özellikler de dahil olmak üzere pencere öğesi tanımları
Dosyalar Uzantı paketine eklenecek tüm dosyalar

Tam bildirim dökümantasyonu için Uzantı bildirimi referansı sayfasına bakın.

6. Adım: Uzantınızı paketleme ve yayımlama

Uzantınızı paketleyip Visual Studio Market'te yayımlayın.

Paketleme aracını yükleme

npm i -g tfx-cli

Uzantı paketinizi oluşturma

Proje dizininizden şunu çalıştırın:

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

Bu eylem, paketlenmiş uzantınızı içeren bir .vsix dosya oluşturur.

Yayımcı ayarlama

  1. Visual Studio Market Yayımlama Portalı'na gidin.
  2. Oturum açın ve yayımcınız yoksa bir tane oluşturun.
  3. Benzersiz bir yayımcı tanımlayıcısı seçin (bildirim dosyanızda kullanılır).
  4. "fabrikam" yerine yayımcı adınızı kullanmak için vss-extension.json güncelleyin.

Uzantınızı karşıya yükleyin

  1. Yayımlama Portalı'nda Yeni uzantıyı yükle'yi seçin.
  2. Dosyanızı .vsix seçin ve karşıya yükleyin.
  3. Uzantıyı Azure DevOps kuruluşunuzla paylaşın.

Alternatif olarak, komut satırını kullanın:

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

İpucu

Mevcut bir uzantıyı güncelleştirirken sürüm numarasını otomatik olarak artırmak için kullanın --rev-version .

7. Adım: Pencere öğenizi yükleyin ve test edin

Test yapmak için widget'ınızı bir gösterge panosuna ekleyin.

  1. Azure DevOps projenize gidin: https://dev.azure.com/{Your_Organization}/{Your_Project}.
  2. Genel Bakış>Panoları'na gidin.
  3. Widget ekle'yi seçin.
  4. Katalogda pencere öğesinizi bulun ve Ekle'yi seçin.

"Merhaba Dünya" pencere öğesi panoda görüntülenir ve yapılandırdığınız metin görüntülenir.

Sonraki adım: Azure DevOps REST API'lerini pencere öğesinizle tümleştirmeyi öğrenmek için 2. Bölüm'e geçin.

Bölüm 2: Azure DevOps REST API ile Merhaba Dünya

Azure DevOps verileriyle REST API'leri kullanarak etkileşim kuracak şekilde widget'ınızı genişletin. Bu örnekte sorgu bilgilerinin nasıl getirilip pencere öğelerinizde dinamik olarak görüntüleneceği gösterilmektedir.

Bu bölümde, var olan bir sorgu hakkındaki bilgileri almak ve "Merhaba Dünya" metninin altında sorgu ayrıntılarını görüntülemek için İş Öğesi İzleme REST API'sini kullanın.

WorkItemTracking için REST API'sini kullanan örnek pencere öğesiyle Genel Bakış panosunun ekran görüntüsü.

1. Adım: Gelişmiş HTML dosyasını oluşturma

Önceki örneği temel alan yeni bir pencere öğesi dosyası oluşturun. Kopyalayıp hello-world.html olarak hello-world2.htmlyeniden adlandırın. Proje yapınız artık şunları içerir:

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

Pencere öğesi HTML yapısını güncelle

şu değişiklikleri yapın hello-world2.html:

  1. Sorgu verileri için kapsayıcı ekleme: Sorgu bilgilerini görüntülemek için yeni <div> bir öğe ekleyin.
  2. Pencere öğesi tanımlayıcısını güncelleştirme: Benzersiz tanımlama için pencere öğesi adını olarak HelloWorldWidgetHelloWorldWidget2 değiştirin.
<!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>

2. Adım: API erişim izinlerini yapılandırma

REST API çağrıları yapmadan önce, uzantı bildiriminizde gerekli izinleri yapılandırın.

İş kapsamını ekleme

Kapsam, vso.work iş öğelerine ve sorgulara salt okunur erişim verir. Bu kapsamı alanınıza vss-extension.jsonekleyin:

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

Tamamlanmış manifesto örneği

Diğer özelliklere sahip eksiksiz bir bildirim için bunu şu şekilde yapılandırabilirsiniz:

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

Önemli

Kapsam sınırlamaları: Yayımlamadan sonra kapsam ekleme veya değiştirme desteklenmez. Uzantınızı zaten yayımladıysanız, önce Market'ten kaldırmanız gerekir. Visual Studio Market Yayımlama Portalı'na gidin, uzantınızı bulun ve Kaldır'ı seçin.

3. Adım: REST API tümleştirmesi uygulama

Azure DevOps, SDK aracılığıyla JavaScript REST istemci kitaplıkları sağlar. Bu kitaplıklar AJAX çağrılarını sarmalar ve API yanıtlarını kullanılabilir nesnelere eşler.

Widget JavaScript'ini güncelleştir

VSS.require çağrısını hello-world2.html içinde İş Öğesi İzleme REST istemcisini ekleyecek şekilde değiştirin.

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

Önemli uygulama ayrıntıları

Bileşen Amaç
WorkItemTrackingRestClient.getClient() İş Öğesi İzleme REST istemcisinin bir örneğini alır
getQuery() Bir promise içinde sarmalanan sorgu bilgilerini alır
WidgetStatusHelper.Failure() Bileşen hataları için tutarlı hata işleme sunmaktadır
projectId API çağrıları için geçerli proje bağlamı gerekiyor

İpucu

Özel sorgu yolları: "Paylaşılan Sorgular" içinde "Geri Bildirim" sorgunuz yoksa, "Shared Queries/Feedback" öğesini, projenizde var olan herhangi bir sorgunun yoluyla değiştirin.

4. Adım: API yanıt verilerini görüntüleme

REST API yanıtını işleyerek pencere öğenizde sorgu bilgilerini oluşturun.

Sorgu verilerini görüntüleme ekleme

// Process query data Açıklamasını şu uygulamayla değiştirin:

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

yöntemi, getQuery() sorgu meta verileri için özelliklere sahip bir Contracts.QueryHierarchyItem nesne döndürür. Bu örnekte, "Merhaba Dünya" metninin altında üç önemli bilgi parçası görüntülenir.

Tam çalışma örneği

Son hello-world2.html dosyanız şu şekilde görünmelidir:

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

5. Adım: Uzantı bildirimini güncelleştirme

Pencere öğesi kataloğunda kullanılabilir hale getirmek için yeni pencere öğesinizi uzantı bildirimine ekleyin.

İkinci widget katkısını ekle

REST API özellikli pencere öğesinizi içerecek şekilde güncelleştirin vss-extension.json . Diziye şu katkıyı contributions ekleyin:

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

İpucu

Önizleme görüntüsü: Bir görüntü (330x160 piksel) oluşturun preview2.png ve kullanıcılara pencere öğenizin katalogda img nasıl göründüğünü göstermek için bu görüntüyü klasöre yerleştirin.

6. Adım: Paketleme, yayımlama ve paylaşma

Uzantınızı paketleyin, yayımlayın ve paylaşın. Uzantıyı zaten yayımladıysanız doğrudan Market'te yeniden paketleyebilir ve güncelleştirebilirsiniz.

7. Adım: REST API pencere öğesinizi test edin

REST API tümleştirmesini uygulamada görüntülemek için yeni pencere öğesini panonuza ekleyin:

  1. Azure DevOps projenize gidin: https://dev.azure.com/{Your_Organization}/{Your_Project}.
  2. Genel Bakış>Panoları'nu seçin.
  3. Widget ekle'yi seçin.
  4. "Merhaba Dünya Pencere Öğesi 2 (API ile)" öğesini bulun ve Ekle'yi seçin.

Gelişmiş pencere öğesiniz hem "Merhaba Dünya" metnini hem de Azure DevOps projenizdeki canlı sorgu bilgilerini görüntüler.

Sonraki adımlar: Kullanıcıların hangi sorguyu görüntüleyeceklerini özelleştirmelerine olanak tanıyan yapılandırma seçenekleri eklemek için 3. Bölüm'e geçin.

Bölüm 3: Merhaba Dünya Yapılandırma

Widget'ınıza kullanıcı yapılandırma yetenekleri ekleyerek 2. Bölüm üzerine inşa edin. Sorgu yolunu sabit kodlamak yerine, kullanıcıların canlı önizleme işlevselliğiyle hangi sorgunun görüntüleneceğini seçmesine olanak tanıyan bir yapılandırma arabirimi oluşturun.

Bu bölümde, kullanıcıların yapılandırma sırasında gerçek zamanlı geri bildirim sağlarken kendi ihtiyaçlarına göre özelleştirebilecekleri yapılandırılabilir pencere öğelerinin nasıl oluşturulacağı gösterilmektedir.

Değişikliklere göre pencere öğesinin Genel Bakış panosu canlı önizlemesinin ekran görüntüsü.

1. Adım: Yapılandırma dosyaları oluşturma

Pencere öğesi yapılandırmaları pencere öğeleriyle birçok benzerliği paylaşır; her ikisi de aynı SDK, HTML yapısı ve JavaScript desenlerini kullanır, ancak uzantı çerçevesi içinde farklı amaçlara hizmet eder.

Proje yapısını ayarlama

Pencere öğesi yapılandırmasını desteklemek için iki yeni dosya oluşturun:

  1. hello-world2.html kopyalayın ve hello-world3.html, yapılandırılabilir pencere öğeniz olarak yeniden adlandırın.
  2. Yapılandırma arabirimini işleyen adlı configuration.htmlyeni bir dosya oluşturun.

Proje yapınız artık şunları içerir:

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

Yapılandırma arabirimini oluşturma

Sorgu seçmek için bir açılan seçici oluşturan bu HTML yapısını configuration.htmlöğesine ekleyin:

<!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. Adım: Yapılandırma JavaScript'i uygulama

Yapılandırma JavaScript, pencere öğeleriyle aynı başlatma desenini izler, ancak temel IWidget sözleşmesi yerine IWidgetConfiguration sözleşmesini uygular.

Yapılandırma mantığı ekleme

configuration.html bölümüne <head> bu betiği ekleyin.

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

Yapılandırma sözleşmesi ayrıntıları

Sözleşme şu IWidgetConfiguration temel işlevleri gerektirir:

İşlev Amaç Çağrıldığında
load() Yapılandırma kullanıcı arabirimini mevcut ayarlarla başlatma Yapılandırma iletişim kutusu açıldığında
onSave() Kullanıcı girişini seri hale getirme ve ayarları doğrulama Kullanıcı Kaydet'i seçtiğinde

İpucu

Veri serileştirme: Bu örnek, ayarları seri hale getirmek için JSON kullanır. Widget bu ayarlara widgetSettings.customSettings.data aracılığıyla erişir ve bunları uygun şekilde seri hale getirilmelidir.

3. Adım: Canlı önizleme işlevselliğini etkinleştirme

Canlı önizleme, kullanıcıların yapılandırma ayarlarını değiştirirken pencere öğesi değişikliklerini hemen görmesine olanak tanır ve kaydetmeden önce anında geri bildirim sağlar.

Değişiklik bildirimlerini uygulama

Canlı önizlemeyi etkinleştirmek için bu olay işleyicisini işlevine load ekleyin:

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

Yapılandırma dosyasını tamamlama

Finaliniz configuration.html şu şekilde görünmelidir:

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

Önemli

Kaydet düğmesini etkinleştir: Çerçeve, Kaydet düğmesini etkinleştirmek için en az bir yapılandırma değişikliği bildirimi gerektirir. Değişiklik olay işleyicisi, kullanıcılar bir seçenek seçtiğinde bu eylemin gerçekleşmesini sağlar.

4. Adım: Pencere öğesini yapılandırılabilir hale getirme

2. Bölümdeki aracınızı, sabit kodlanmış değerler yerine yapılandırma verilerini kullanarak dönüştürün. Bu adım, sözleşmenin IConfigurableWidget uygulanmasını gerektirir.

Pencere öğesi kaydını güncelleştirme

içinde hello-world3.htmlşu değişiklikleri yapın:

  1. Pencere öğesi kimliği güncelleniyor: HelloWorldWidget2'den HelloWorldWidget3'ye değiştiriliyor.
  2. Yeniden yükleme işlevi ekleme: Sözleşmeyi IConfigurableWidget uygulayın.
return {
    load: function (widgetSettings) {
        // Set your title
        var $title = $('h2.title');
        $title.text('Hello World');

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

Yapılandırma verilerini işleme

İşlevi getQueryInfo sabit kodlanmış sorgu yolları yerine yapılandırma ayarlarını kullanacak şekilde güncelleştirin:

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

Widget yaşam döngüsü farklılıkları

İşlev Amaç Kullanım yönergeleri
load() İlk widget oluşturma ve tek seferlik kurulum Ağır işlemler, kaynakların başlatılması
reload() Widget'i yeni yapılandırmayla güncelleştirme Basit güncelleştirmeler, veri yenileme

İpucu

Performans iyileştirme: Yalnızca bir kez çalıştırılması gereken pahalı işlemler ve reload() yapılandırma değiştiğinde hızlı güncelleştirmeler için kullanınload().

(İsteğe bağlı) Ayrıntılı bilgi için lightbox ekleme

Pano pencere öğelerinin alanı sınırlıdır ve bu da kapsamlı bilgilerin görüntülenmesini zorlaştırır. Lightbox, panodan uzaklaşmadan ayrıntılı verileri modlar arayüzünde göstererek zarif bir çözüm sunar.

Widget'larda neden bir lightbox kullanmalısınız?

Fayda Açıklama
Alan verimliliği Ayrıntılı görünümler sunarken pencere öğesini kompakt tutun
Kullanıcı deneyimi Pano bağlamını koruyarak daha fazla bilgi gösterme
Aşamalı açıklama Pencere öğesinde özet verileri, isteğe bağlı ayrıntıları gösterme
Esnek tasarım Farklı ekran boyutlarına ve pencere öğesi yapılandırmalarına uyum sağlama

Tıklanabilir öğeleri uygulama

Sorgu verileri işlemenizi lightbox'ı tetikleyen tıklanabilir öğeleri içerecek şekilde güncelleştirin:

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

Lightbox işlevini oluşturma

Bu lightbox uygulamasını pencere öğesi JavaScript'inize ekleyin:

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

Lightbox stilini ekle

Pencere öğesi HTML <head> bölümünüzde lightbox için CSS stilleri ekleyin:

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

Gelişmiş pencere öğesi uygulaması

Tamamen geliştirilmiş ve lightbox işlevselliğine sahip pencere öğeniz:

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

Erişilebilirlikle ilgili dikkat edilmesi gerekenler: Lightbox'ınızın klavyeyle erişilebilir olduğundan ve ekran okuyucular için uygun etiketler içerdiğine emin olun. Azure DevOps'un yerleşik erişilebilirlik özellikleriyle test edin.

Önemli

Performans: Lightbox'lar hızla yüklenmelidir. Ayrıntılı verileri, her şeyi önceden getirmek yerine yalnızca ışık kutusu açıldığında yavaş yüklemeyi göz önünde bulundurun.

5. Adım: Uzantı bildirimini yapılandırma

Hem yapılandırılabilir pencere öğesini hem de yapılandırma arabirimini uzantı bildiriminize kaydedin.

Pencere öğesi ve yapılandırma katkıları ekleme

İki yeni katkı içerecek şekilde güncelleştirin vss-extension.json :

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

Yapılandırma katkı gereksinimleri

Özellik Amaç Gerekli değer
type Katkıyı pencere öğesi yapılandırması olarak tanımlar ms.vss-dashboards-web.widget-configuration
targets Yapılandırmanın görüntülendiği yer ms.vss-dashboards-web.widget-configuration
uri Yapılandırma HTML dosyasının yolu Yapılandırma dosya yolunuz

Pencere öğesi hedefleme düzeni

Yapılandırılabilir pencere öğeleri için targets dizi, yapılandırmaya bir başvuru içermelidir:

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

Uyarı

Yapılandırma düğmesi görünürlüğü: Pencere öğesi yapılandırma katkısını düzgün bir şekilde hedeflemiyorsa Yapılandır düğmesi görünmez. Yayımcı ve uzantı adlarının bildiriminizle tam olarak eşleşip eşleşmedığını doğrulayın.

6. Adım: Paketleme, yayımlama ve paylaşma

Gelişmiş uzantınızı yapılandırma özellikleriyle dağıtın.

İlk yayınınızsa 6. Adım: Paketleme, yayımlama ve paylaşma adımlarını izleyin. Mevcut uzantılar için doğrudan Market'te yeniden paketleyin ve güncelleştirin.

7. Adım: Yapılandırılabilir pencere öğesini test edin

Bileşeninizi ekleyip yapılandırarak tam yapılandırma iş akışını deneyimleyin.

Araç takvimini kontrol panelinize ekleyin

  1. https://dev.azure.com/{Your_Organization}/{Your_Project}'e gidin.
  2. Genel Bakış>Panoları'na gidin.
  3. Widget ekle'yi seçin.
  4. "Merhaba Dünya Pencere Öğesi 3 (yapılandırma ile)" öğesini bulun ve Ekle'yi seçin.

Widget kurulumu gerektirdiğinden bir yapılandırma istemi görüntülenir.

Katalogdan örnek bir pencere öğesi içeren Genel Bakış panosunun ekran görüntüsü.

Pencere öğesini yapılandırın

Yapılandırmaya iki yöntemden biriyle erişin:

  • Widget menüsü: Widget'ın üzerine gelin, üç noktayı (⋯) seçin ve Yapılandır seçeneğini seçin.
  • Pano düzenleme modu: PanodaDüzenle'yi ve ardından pencere öğesindeki yapılandır düğmesini seçin

Yapılandırma paneli, ortada canlı önizleme ile açılır. Hemen güncelleştirmeleri görmek için açılan listeden bir sorgu seçin ve ardından değişikliklerinizi uygulamak için Kaydet'i seçin.

8. Adım: Gelişmiş yapılandırma seçenekleri ekleme

Pencere öğenizi, özel adlar ve boyutlar gibi daha fazla entegre yapılandırma özelliğiyle genişletin.

Ad ve boyut yapılandırmasını etkinleştirme

Azure DevOps, hazır gelen iki yapılandırılabilir özellik sunar.

Özellik Bildirim özelliği Amaç
Özel adlar isNameConfigurable: true Kullanıcılar varsayılan pencere öğesi adını geçersiz kılabilir
Birden çok boyut Birden çok supportedSizes girdi Kullanıcılar pencere öğelerini yeniden boyutlandırabilir

Gelişmiş bildirim örneği

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

Yapılandırılmış adları görüntüle

Özel pencere öğesi adlarını göstermek için pencere öğenizi widgetSettings.name kullanacak şekilde güncelleyin.

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

Uzantınızı güncelleştirdikten sonra hem pencere öğesi adını hem de boyutunu yapılandırabilirsiniz:

Pencere öğesi adının ve boyutunun yapılandırılabildiği yeri gösteren ekran görüntüsü.

Bu gelişmiş yapılandırma seçeneklerini etkinleştirmek için uzantınızı yeniden paketleyin ve güncelleştirin.

Tebrikler! Canlı önizleme özellikleri ve kullanıcı özelleştirme seçenekleriyle eksiksiz, yapılandırılabilir bir Azure DevOps pano pencere öğesi oluşturdunuz.