Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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.
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ündelogo.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ündepreview.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
- Visual Studio Market Yayımlama Portalı'na gidin.
- Oturum açın ve yayımcınız yoksa bir tane oluşturun.
- Benzersiz bir yayımcı tanımlayıcısı seçin (bildirim dosyanızda kullanılır).
- "fabrikam" yerine yayımcı adınızı kullanmak için
vss-extension.json
güncelleyin.
Uzantınızı karşıya yükleyin
- Yayımlama Portalı'nda Yeni uzantıyı yükle'yi seçin.
- Dosyanızı
.vsix
seçin ve karşıya yükleyin. - 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.
- Azure DevOps projenize gidin:
https://dev.azure.com/{Your_Organization}/{Your_Project}
. - Genel Bakış>Panoları'na gidin.
- Widget ekle'yi seçin.
- 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.
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.html
yeniden 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
:
-
Sorgu verileri için kapsayıcı ekleme: Sorgu bilgilerini görüntülemek için yeni
<div>
bir öğe ekleyin. -
Pencere öğesi tanımlayıcısını güncelleştirme: Benzersiz tanımlama için pencere öğesi adını olarak
HelloWorldWidget
HelloWorldWidget2
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.json
ekleyin:
{
"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:
- Azure DevOps projenize gidin:
https://dev.azure.com/{Your_Organization}/{Your_Project}
. - Genel Bakış>Panoları'nu seçin.
- Widget ekle'yi seçin.
- "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.
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:
-
hello-world2.html
kopyalayın vehello-world3.html
, yapılandırılabilir pencere öğeniz olarak yeniden adlandırın. - Yapılandırma arabirimini işleyen adlı
configuration.html
yeni 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:
-
Pencere öğesi kimliği güncelleniyor:
HelloWorldWidget2
'denHelloWorldWidget3
'ye değiştiriliyor. -
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">×</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
-
https://dev.azure.com/{Your_Organization}/{Your_Project}
'e gidin. - Genel Bakış>Panoları'na gidin.
- Widget ekle'yi seçin.
- "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.
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:
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.