Menambahkan widget dasbor
Layanan Azure DevOps | Azure DevOps Server 2022 - Azure DevOps Server 2019
Widget di dasbor diimplementasikan sebagai kontribusi dalam kerangka kerja ekstensi. Satu ekstensi dapat memiliki beberapa kontribusi. Pelajari cara membuat ekstensi dengan beberapa widget sebagai kontribusi.
Artikel ini dibagi menjadi tiga bagian, masing-masing bangunan pada sebelumnya - dimulai dengan widget sederhana dan diakhir dengan widget komprehensif.
Tip
Lihat dokumentasi terbaru kami tentang pengembangan ekstensi menggunakan Azure DevOps Extension SDK.
Prasyarat
- Pengetahuan: Beberapa pengetahuan tentang JavaScript, HTML, CSS diperlukan untuk pengembangan widget.
- Organisasi di Azure DevOps.
- Editor teks. Untuk banyak tutorial, kami menggunakan Visual Studio Code.
- Versi node terbaru.
- CLI lintas platform untuk Azure DevOps (tfx-cli) untuk mengemas ekstensi Anda.
- tfx-cli dapat diinstal menggunakan
npm
, komponen Node.js dengan menjalankannpm i -g tfx-cli
- tfx-cli dapat diinstal menggunakan
- Direktori rumah untuk proyek Anda. Direktori ini disebut sebagai
home
sepanjang tutorial.
Struktur file ekstensi:
|--- 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
Dalam tutorial ini
- Bagian 1: Menunjukkan kepada Anda cara membuat widget baru, yang mencetak pesan "Halo Dunia" sederhana.
- Bagian 2: Dibangun pada bagian pertama dengan menambahkan panggilan ke REST API Azure DevOps.
- Bagian 3: Menjelaskan cara menambahkan konfigurasi ke widget Anda.
Catatan
Jika Anda terburu-buru dan ingin segera mendapatkan kode, Anda dapat mengunduh sampel.
Setelah diunduh, buka widgets
folder, lalu ikuti Langkah 6 dan Langkah 7 secara langsung untuk menerbitkan ekstensi sampel yang memiliki tiga widget sampel dari berbagai kompleksitas.
Mulailah dengan beberapa gaya dasar untuk widget yang kami berikan di luar kotak dan beberapa panduan tentang struktur widget.
Bagian 1: Halo Dunia
Bagian 1 menyajikan widget yang mencetak "Halo Dunia" menggunakan JavaScript.
Langkah 1: Dapatkan SDK klien - VSS.SDK.min.js
Skrip SDK inti, VSS.SDK.min.js
, memungkinkan ekstensi web untuk berkomunikasi ke bingkai Azure DevOps host. Skrip melakukan operasi seperti menginisialisasi, memberi tahu ekstensi dimuat, atau mendapatkan konteks tentang halaman saat ini.
Dapatkan file SDK VSS.SDK.min.js
Klien dan tambahkan ke aplikasi web Anda. Tempatkan di home/sdk/scripts
folder .
Untuk mengambil SDK, gunakan perintah 'npm install':
npm install vss-web-extension-sdk
Untuk informasi selengkapnya, lihat halaman GitHub SDK Klien.
Langkah 2: Siapkan halaman HTML Anda - hello-world.html
Halaman HTML Anda adalah lem yang menyimpan tata letak Anda bersama-sama dan menyertakan referensi ke CSS dan JavaScript. Anda dapat menamai file ini apa pun. Perbarui semua referensi ke hello-world
dengan nama yang Anda gunakan.
Widget Anda berbasis HTML dan dihosting dalam iframe.
Tambahkan HTML berikut di hello-world.html
. Kami menambahkan referensi wajib ke VSS.SDK.min.js
file dan menyertakan h2
elemen, yang diperbarui dengan string Halo Dunia pada langkah mendatang.
<!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>
Meskipun kita menggunakan file HTML, sebagian besar elemen kepala HTML selain skrip dan tautan diabaikan oleh kerangka kerja.
Langkah 3: Perbarui JavaScript
Kami menggunakan JavaScript untuk merender konten di widget. Dalam artikel ini, kami membungkus semua kode JavaScript kami di dalam <script>
elemen dalam file HTML. Anda dapat memilih untuk memiliki kode ini dalam file JavaScript terpisah dan merujuknya dalam file HTML.
Kode merender konten. Kode JavaScript ini juga menginisialisasi VSS SDK, memetakan kode untuk widget Anda ke nama widget Anda, dan memberi tahu kerangka kerja ekstensi keberhasilan atau kegagalan widget.
Dalam kasus kami, kode berikut mencetak "Halo Dunia" di widget. Tambahkan elemen ini script
di 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
menginisialisasi jabat tangan antara iframe yang menghosting widget dan bingkai host.- Kami meneruskan
explicitNotifyLoaded: true
sehingga widget dapat secara eksplisit memberi tahu host ketika selesai memuat. Kontrol ini memungkinkan kami untuk memberi tahu penyelesaian beban setelah memastikan bahwa modul dependen dimuat. Kami meneruskanusePlatformStyles: true
sehingga widget dapat menggunakan gaya inti Azure DevOps untuk elemen HTML (seperti isi, div, dan sebagainya). Jika widget lebih suka tidak menggunakan gaya ini, mereka dapat meneruskanusePlatformStyles: false
. VSS.require
digunakan untuk memuat pustaka skrip VSS yang diperlukan. Panggilan ke metode ini secara otomatis memuat pustaka umum seperti JQuery dan JQueryUI. Dalam kasus kami, kami bergantung pada pustaka WidgetHelpers, yang digunakan untuk mengkomunikasikan status widget ke kerangka kerja widget. Jadi, kami meneruskan namaTFS/Dashboards/WidgetHelpers
modul yang sesuai dan panggilan balik keVSS.require
. Panggilan balik dipanggil setelah modul dimuat. Panggilan balik memiliki sisa kode JavaScript yang diperlukan untuk widget. Di akhir panggilan balik, kami memanggilVSS.notifyLoadSucceeded
untuk memberi tahu penyelesaian beban.WidgetHelpers.IncludeWidgetStyles
termasuk lembar gaya dengan beberapa css dasar untuk memulai. Untuk menggunakan gaya ini, bungkus konten Anda di dalam elemen HTML dengan kelaswidget
.VSS.register
digunakan untuk memetakan fungsi di JavaScript, yang secara unik mengidentifikasi widget di antara berbagai kontribusi dalam ekstensi Anda. Nama harus cocok denganid
yang mengidentifikasi kontribusi Anda seperti yang dijelaskan di Langkah 5. Untuk widget, fungsi yang diteruskan harusVSS.register
mengembalikan objek yang memenuhiIWidget
kontrak, misalnya, objek yang dikembalikan harus memiliki properti beban yang nilainya adalah fungsi lain yang memiliki logika inti untuk merender widget. Dalam kasus kami, ini untuk memperbarui teksh2
elemen ke "Halo Dunia." Fungsi inilah yang dipanggil ketika kerangka kerja widget membuat instans widget Anda. Kami menggunakanWidgetStatusHelper
dari WidgetHelpers untuk mengembalikan sebagai suksesWidgetStatus
.
Peringatan
Jika nama yang digunakan untuk mendaftarkan widget tidak cocok dengan ID untuk kontribusi dalam manifes, maka widget berfungsi secara tidak terduga.
vss-extension.json
harus selalu berada di akar folder (dalam panduan ini,HelloWorld
). Untuk semua file lainnya, Anda dapat menempatkannya dalam struktur apa pun yang Anda inginkan di dalam folder, cukup pastikan untuk memperbarui referensi dengan tepat dalam file HTML dan dalamvss-extension.json
manifes.
Langkah 4: Perbarui logo ekstensi Anda: logo.png
Logo Anda ditampilkan di Marketplace dan di katalog widget setelah pengguna menginstal ekstensi Anda.
Anda memerlukan ikon katalog 98 px x 98 px. Pilih gambar, beri nama logo.png
, dan letakkan img
di folder .
Anda dapat memberi nama gambar ini sesampainya selama manifes ekstensi di langkah berikutnya diperbarui dengan nama yang Anda gunakan.
Langkah 5: Buat manifes ekstensi Anda: vss-extension.json
Setiap ekstensi harus memiliki file manifes ekstensi.
- Baca referensi manifes ekstensi.
- Cari tahu lebih lanjut tentang titik kontribusi di Poin ekstensibilitas.
- Buat file json (
vss-extension.json
, misalnya) dihome
direktori dengan konten berikut:
{
"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
}
]
}
Untuk informasi selengkapnya tentang atribut yang diperlukan, lihat Referensi manifes Ekstensi.
Catatan
Ubah penerbit ke nama penerbit Anda. Untuk membuat penerbit, lihat Paket/Terbitkan/Instal.
Ikon
Ikon stanza menentukan jalur ke ikon ekstensi Anda dalam manifes Anda.
Kontribusi
Setiap entri kontribusi mendefinisikan properti.
- ID untuk mengidentifikasi kontribusi Anda. ID ini harus unik dalam ekstensi. ID ini harus cocok dengan nama yang Anda gunakan di Langkah 3 untuk mendaftarkan widget Anda.
- Jenis kontribusi. Untuk semua widget, jenisnya harus
ms.vss-dashboards-web.widget
. - Array target tempat kontribusi berkontribusi. Untuk semua widget, targetnya harus
[ms.vss-dashboards-web.widget-catalog]
. - Properti adalah objek yang menyertakan properti untuk jenis kontribusi. Untuk widget, properti berikut wajib.
Properti | Deskripsi |
---|---|
nama | Nama widget yang akan ditampilkan di katalog widget. |
description | Deskripsi widget untuk ditampilkan di katalog widget. |
catalogIconUrl | Jalur relatif ikon katalog yang Anda tambahkan di Langkah 4 untuk ditampilkan di katalog widget. Gambar harus 98 px x 98 px. Jika Anda menggunakan struktur folder yang berbeda atau nama file yang berbeda, tentukan jalur relatif yang sesuai di sini. |
previewImageUrl | Jalur relatif gambar pratinjau yang Anda tambahkan di Langkah 4 untuk ditampilkan di katalog widget. Gambar harus 330 px x 160 px. Jika Anda menggunakan struktur folder yang berbeda atau nama file yang berbeda, tentukan jalur relatif yang sesuai di sini. |
uri | Jalur relatif file HTML yang Anda tambahkan di Langkah 1. Jika Anda menggunakan struktur folder yang berbeda atau nama file yang berbeda, tentukan jalur relatif yang sesuai di sini. |
supportedSizes | Array ukuran yang didukung oleh widget Anda. Saat widget mendukung beberapa ukuran, ukuran pertama dalam array adalah ukuran default widget. widget size ditentukan untuk baris dan kolom yang ditempati oleh widget di kisi dasbor. Satu baris/kolom sesuai dengan 160 px. Dimensi apa pun yang lebih besar dari 1x1 mendapatkan tambahan 10 px yang mewakili selokan antar widget. Misalnya, widget 160*3+10*2 3x2 lebar dan 160*2+10*1 tinggi. Ukuran maksimum yang didukung adalah 4x4 . |
cakupan yang didukung | Saat ini, hanya dasbor tim yang didukung. Nilainya harus project_team . Pembaruan di masa mendatang mungkin menyertakan lebih banyak opsi untuk cakupan dasbor. |
File
Stanza file menyatakan file yang ingin Anda sertakan dalam paket Anda - halaman HTML Anda, skrip Anda, skrip SDK, dan logo Anda.
Atur addressable
ke true
kecuali Anda menyertakan file lain yang tidak perlu dapat diatasi URL.
Catatan
Untuk informasi selengkapnya tentang file manifes ekstensi, seperti propertinya dan apa yang mereka lakukan, lihat referensi manifes ekstensi.
Langkah 6: Mengemas, menerbitkan, dan berbagi
Setelah Anda memiliki ekstensi tertulis, langkah selanjutnya untuk memasukkannya ke Marketplace adalah mengemas semua file Anda bersama-sama. Semua ekstensi dimas sebagai file .vsix yang kompatibel dengan VSIX 2.0 - Microsoft menyediakan antarmuka baris perintah lintas platform (CLI) untuk mengemas ekstensi Anda.
Mendapatkan alat pengemasan
Anda dapat menginstal atau memperbarui CLI Lintas platform untuk Azure DevOps (tfx-cli) menggunakan npm
, komponen Node.js, dari baris perintah Anda.
npm i -g tfx-cli
Mengemas ekstensi Anda
Mengemas ekstensi Anda ke dalam file .vsix mudah setelah Anda memiliki tfx-cli. Buka direktori beranda ekstensi Anda dan jalankan perintah berikut.
tfx extension create --manifest-globs vss-extension.json
Catatan
Versi ekstensi/integrasi harus ditahapkan pada setiap pembaruan.
Saat Anda memperbarui ekstensi yang ada, perbarui versi dalam manifes atau teruskan sakelar --rev-version
baris perintah. Ini akan menaikkan nomor versi patch ekstensi Anda dan menyimpan versi baru ke manifes Anda.
Setelah mengemas ekstensi dalam file .vsix, Anda siap untuk menerbitkan ekstensi Anda ke Marketplace.
Membuat penerbit untuk ekstensi
Semua ekstensi, termasuk ekstensi dari Microsoft, diidentifikasi sebagai disediakan oleh penerbit. Jika Anda belum menjadi anggota penerbit yang sudah ada, buatlah.
- Masuk ke Portal Penerbitan Marketplace Visual Studio
- Jika Anda belum menjadi anggota penerbit yang sudah ada, Anda harus membuat penerbit. Jika Anda sudah memiliki penerbit, gulir ke dan pilih Terbitkan Ekstensi di bawah Situs Terkait.
- Tentukan pengidentifikasi untuk penerbit Anda, misalnya:
mycompany-myteam
- Pengidentifikasi digunakan sebagai nilai untuk
publisher
atribut dalam file manifes ekstensi Anda.
- Pengidentifikasi digunakan sebagai nilai untuk
- Tentukan nama tampilan untuk penerbit Anda, misalnya:
My Team
- Tentukan pengidentifikasi untuk penerbit Anda, misalnya:
- Tinjau Perjanjian Penerbit Marketplace dan pilih Buat.
Sekarang penerbit Anda ditentukan. Dalam rilis mendatang, Anda dapat memberikan izin untuk melihat dan mengelola ekstensi penerbit Anda.
Menerbitkan ekstensi di bawah penerbit umum menyederhanakan proses untuk tim dan organisasi, menawarkan pendekatan yang lebih aman. Metode ini menghilangkan kebutuhan untuk mendistribusikan satu set kredensial di antara beberapa pengguna, meningkatkan keamanan dan
vss-extension.json
Perbarui file manifes dalam sampel untuk mengganti ID fabrikam
penerbit dummy dengan ID penerbit Anda.
Menerbitkan dan berbagi ekstensi
Sekarang, Anda sekarang dapat mengunggah ekstensi Anda ke Marketplace.
Pilih Unggah ekstensi baru, buka file .vsix paket Anda, dan pilih Unggah.
Anda juga dapat mengunggah ekstensi melalui baris perintah dengan menggunakan tfx extension publish
perintah alih-alih tfx extension create
mengemas dan menerbitkan ekstensi Anda dalam satu langkah.
Anda dapat secara opsional menggunakan --share-with
untuk berbagi ekstensi Anda dengan satu atau beberapa akun setelah penerbitan.
Anda juga memerlukan token akses pribadi.
tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization
Langkah 7: Tambahkan widget dari katalog
Masuk ke proyek Anda,
http://dev.azure.com/{Your_Organization}/{Your_Project}
.Pilih Dasbor Gambaran Umum>.
Pilih Tambahkan widget.
Sorot widget Anda, lalu pilih Tambahkan.
Widget muncul di dasbor Anda.
Bagian 2: Halo Dunia dengan REST API Azure DevOps
Widget dapat memanggil salah satu REST API di Azure DevOps untuk berinteraksi dengan sumber daya Azure DevOps. Dalam contoh berikut, kami menggunakan REST API untuk WorkItemTracking untuk mengambil informasi tentang kueri yang ada dan menampilkan beberapa info kueri di widget di bawah teks "Halo Dunia".
Langkah 1: Tambahkan file HTML
Salin file hello-world.html
dari contoh sebelumnya, dan ganti nama salinan menjadi hello-world2.html
. Folder Anda sekarang terlihat seperti contoh berikut:
|--- README.md |--- node_modules
|--- SDK
|--- skrip |--- VSS. SDK.min.js |--- img |--- logo.png |--- skrip
Halaman |--- hello-world.html // html yang akan digunakan untuk widget |--- hello-world2.html // salinan manifes ekstensi hello-world.html |--- vss-extension.json //
Untuk menyimpan informasi kueri, tambahkan elemen baru div
di h2
bawah .
Perbarui nama widget dari HelloWorldWidget
ke HelloWorldWidget2
di baris tempat Anda memanggil VSS.register
.
Tindakan ini memungkinkan kerangka kerja mengidentifikasi widget secara unik dalam ekstensi.
<!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>
Langkah 2: Mengakses sumber daya Azure DevOps
Untuk mengaktifkan akses ke sumber daya Azure DevOps, cakupan perlu ditentukan dalam manifes ekstensi. Kami menambahkan cakupan ke vso.work
manifes kami.
Cakupan ini menunjukkan widget memerlukan akses baca-saja ke kueri dan item kerja. Lihat semua cakupan yang tersedia di sini.
Tambahkan kode berikut di akhir manifes ekstensi Anda.
{
"scopes":[
"vso.work"
]
}
Untuk menyertakan properti lain, Anda harus mencantumkannya secara eksplisit, misalnya:
{
"name": "example-widget",
"publisher": "example-publisher",
"version": "1.0.0",
"scopes": [
"vso.work"
]
}
Peringatan
Menambahkan atau mengubah cakupan setelah menerbitkan ekstensi saat ini tidak didukung. Jika Anda sudah mengunggah ekstensi, hapus ekstensi tersebut dari Marketplace. Buka Portal Penerbitan Marketplace Visual Studio, pilih kanan ekstensi Anda dan pilih Hapus.
Langkah 3: Lakukan Panggilan REST API
Ada banyak pustaka sisi klien yang dapat diakses melalui SDK untuk melakukan panggilan REST API di Azure DevOps. Pustaka ini disebut klien REST dan merupakan pembungkus JavaScript di sekitar panggilan Ajax untuk semua titik akhir sisi server yang tersedia. Anda dapat menggunakan metode yang disediakan oleh klien ini alih-alih menulis panggilan Ajax sendiri. Metode ini memetakan respons API ke objek yang dapat digunakan kode Anda.
Dalam langkah ini, kami memperbarui VSS.require
panggilan untuk memuat AzureDevOps/WorkItemTracking/RestClient
, yang menyediakan klien WORKItemTracking REST.
Kita dapat menggunakan klien REST ini untuk mendapatkan informasi tentang kueri yang disebut Feedback
di bawah folder Shared Queries
.
Di dalam fungsi yang kita teruskan ke VSS.register
, kita membuat variabel untuk menahan ID proyek saat ini. Kita perlu variabel ini untuk mengambil kueri.
Kami juga membuat metode getQueryInfo
baru untuk menggunakan klien REST. Metode ini yang kemudian dipanggil dari metode pemuatan.
Metode getClient
ini memberikan instans klien REST yang kita butuhkan.
Metode getQuery
mengembalikan kueri yang dibungkus dalam janji.
Tampilan yang diperbarui VSS.require
adalah sebagai berikut:
VSS.require(["AzureDevOps/Dashboards/WidgetHelpers", "AzureDevOps/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();
});
Perhatikan penggunaan metode Kegagalan dari WidgetStatusHelper
.
Ini memungkinkan Anda untuk menunjukkan kepada kerangka kerja widget bahwa kesalahan terjadi dan memanfaatkan pengalaman kesalahan standar yang disediakan untuk semua widget.
Jika Anda tidak memiliki Feedback
kueri di bawah Shared Queries
folder, ganti Shared Queries\Feedback
dalam kode dengan jalur kueri yang ada di proyek Anda.
Langkah 4: Menampilkan respons
Langkah terakhir adalah merender informasi kueri di dalam widget.
Fungsi mengembalikan getQuery
objek jenis Contracts.QueryHierarchyItem
di dalam janji.
Dalam contoh ini, kami menampilkan ID kueri, nama kueri, dan nama pembuat kueri di bawah teks "Halo Dunia".
Ganti komentar // Do something with the query
dengan kode berikut:
// 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);
Final hello-world2.html
Anda seperti contoh berikut:
<!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, 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($('<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>
Langkah 5: Memperbarui manifes ekstensi
Dalam langkah ini, kami memperbarui manifes ekstensi untuk menyertakan entri untuk widget kedua kami.
Tambahkan kontribusi baru ke array di contributions
properti dan tambahkan file hello-world2.html
baru ke array di properti file.
Anda memerlukan gambar pratinjau lain untuk widget kedua. Beri nama ini preview2.png
dan letakkan img
di folder .
{
...,
"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"
]
}
Langkah 6: Mengemas, menerbitkan, dan berbagi
Paket, terbitkan, dan bagikan ekstensi Anda. Jika Anda sudah menerbitkan ekstensi, Anda dapat mengemas ulang ekstensi dan langsung memperbaruinya ke Marketplace.
Langkah 7: Tambahkan widget dari katalog
Sekarang, buka dasbor tim Anda di https:\//dev.azure.com/{Your_Organization}/{Your_Project}
. Jika halaman ini sudah terbuka, maka refresh.
Arahkan mouse ke Edit dan pilih Tambahkan. Katalog widget terbuka di mana Anda menemukan widget yang Anda instal.
Untuk menambahkannya ke dasbor Anda, pilih widget Anda dan pilih Tambahkan.
Bagian 3: Mengonfigurasi Halo Dunia
Di Bagian 2 panduan ini, Anda melihat cara membuat widget yang menampilkan informasi kueri untuk kueri yang dikodekan secara permanen. Di bagian ini, kami menambahkan kemampuan untuk mengonfigurasi kueri yang akan digunakan alih-alih yang dikodekan secara permanen. Saat dalam mode konfigurasi, pengguna akan melihat pratinjau langsung widget berdasarkan perubahannya. Perubahan ini disimpan ke widget di dasbor saat pengguna memilih Simpan.
Langkah 1: Tambahkan file HTML
Implementasi Widget dan Konfigurasi Widget sangat mirip. Keduanya diimplementasikan dalam kerangka kerja ekstensi sebagai kontribusi. Keduanya menggunakan file SDK yang sama, VSS.SDK.min.js
. Keduanya didasarkan pada HTML, JavaScript, dan CSS.
Salin file html-world2.html
dari contoh sebelumnya dan ganti nama salinan menjadi hello-world3.html
. Tambahkan file HTML lain yang disebut configuration.html
.
Folder Anda sekarang terlihat seperti contoh berikut:
|--- 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
Tambahkan HTML berikut di configuration.html
. Kami pada dasarnya menambahkan referensi wajib ke VSS.SDK.min.js
file dan select
elemen untuk dropdown untuk memilih kueri dari daftar prasetel.
<!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>
Langkah 2: Mengonfigurasi JavaScript
Gunakan JavaScript untuk merender konten dalam konfigurasi widget seperti yang kami lakukan untuk widget di Langkah 3 Bagian 1 dalam panduan ini.
Kode JavaScript ini merender konten, menginisialisasi VSS SDK, memetakan kode untuk konfigurasi widget Anda ke nama konfigurasi, dan meneruskan pengaturan konfigurasi ke kerangka kerja. Dalam kasus kami, kode berikut memuat konfigurasi widget.
Buka file configuration.html
dan elemen berikut <script>
ke <head>
.
<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>
VSS.init
,VSS.require
, danVSS.register
memainkan peran yang sama dengan yang mereka mainkan untuk widget seperti yang dijelaskan di Bagian 1. Satu-satunya perbedaan adalah bahwa untuk konfigurasi widget, fungsi yang diteruskan keVSS.register
harus mengembalikan objek yang memenuhiIWidgetConfiguration
kontrak.- Properti
load
IWidgetConfiguration
kontrak harus memiliki fungsi sebagai nilainya. Fungsi ini memiliki serangkaian langkah untuk merender konfigurasi widget. Dalam kasus kami, ini untuk memperbarui nilai yang dipilih dari elemen dropdown dengan pengaturan yang ada jika ada. Fungsi ini dipanggil ketika kerangka kerja membuat instanswidget configuration
- Properti
onSave
IWidgetConfiguration
kontrak harus memiliki fungsi sebagai nilainya. Fungsi ini dipanggil oleh kerangka kerja saat pengguna memilih Simpan di panel konfigurasi. Jika input pengguna siap disimpan, maka serialisasikan ke string, bentukcustom settings
objek dan gunakanWidgetConfigurationSave.Valid()
untuk menyimpan input pengguna.
Dalam panduan ini, kami menggunakan JSON untuk membuat serial input pengguna ke dalam string. Anda dapat memilih cara lain untuk membuat serialisasi input pengguna ke string.
Ini dapat diakses oleh widget melalui properti customSettings objek WidgetSettings
.
Widget harus mendeserialisasi, yang tercakup dalam Langkah 4.
Langkah 3: JavaScript - aktifkan pratinjau langsung
Untuk mengaktifkan pembaruan pratinjau langsung saat pengguna memilih kueri dari dropdown, kami melampirkan penanganan aktivitas perubahan ke tombol . Handler ini memberi tahu kerangka kerja bahwa konfigurasi berubah.
Ini juga meneruskan yang customSettings
akan digunakan untuk memperbarui pratinjau. Untuk memberi tahu kerangka kerja, notify
metode pada perlu dipanggil widgetConfigurationContext
. Dibutuhkan dua parameter, nama peristiwa, yang dalam hal ini adalah WidgetHelpers.WidgetEvent.ConfigurationChange
, dan EventArgs
objek untuk peristiwa, dibuat dari customSettings
dengan bantuan metode pembantu WidgetEvent.Args
.
Tambahkan kode berikut dalam fungsi yang ditetapkan ke load
properti .
$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);
});
Direvisi: Pastikan bahwa kerangka kerja diberi tahu tentang perubahan konfigurasi setidaknya sekali untuk mengaktifkan tombol Simpan .
Pada akhirnya, Anda configuration.html
terlihat seperti contoh berikut:
<!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>
Langkah 4: Terapkan muat ulang di widget - JavaScript
Kami menyiapkan konfigurasi widget untuk menyimpan jalur kueri yang dipilih oleh pengguna.
Kita sekarang harus memperbarui kode di widget untuk menggunakan konfigurasi tersimpan ini alih-alih dikodekan Shared Queries/Feedback
secara permanen dari contoh sebelumnya.
Buka file hello-world3.html
dan perbarui nama widget dari HelloWorldWidget2
ke HelloWorldWidget3
di baris tempat Anda memanggil VSS.register
.
Tindakan ini memungkinkan kerangka kerja mengidentifikasi widget secara unik dalam ekstensi.
Fungsi yang dipetakan melalui HelloWorldWidget3
VSS.register
saat ini mengembalikan objek yang memenuhi IWidget
kontrak.
Karena widget kami sekarang membutuhkan konfigurasi, fungsi ini perlu diperbarui untuk mengembalikan objek yang memenuhi IConfigurableWidget
kontrak.
Untuk melakukannya, perbarui pernyataan pengembalian untuk menyertakan properti yang disebut muat ulang per kode berikut. Nilai untuk properti ini adalah fungsi yang memanggil getQueryInfo
metode sekali lagi.
Metode muat ulang ini dipanggil oleh kerangka kerja setiap kali input pengguna berubah untuk menampilkan pratinjau langsung. Metode reload ini juga dipanggil ketika konfigurasi disimpan.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
return getQueryInfo(widgetSettings);
}
}
Jalur kueri yang dikodekan secara permanen harus diganti dengan jalur kueri yang dikonfigurasi getQueryInfo
, yang dapat diekstrak dari parameter widgetSettings
yang diteruskan ke metode .
Tambahkan kode berikut di awal getQueryInfo
metode dan ganti jalur kueri yang dikodekan secara permanen dengan 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();
}
Pada titik ini, widget Anda siap untuk dirender dengan pengaturan yang dikonfigurasi.
load
Properti dan reload
memiliki fungsi yang sama. Ini adalah kasus untuk widget yang paling sederhana.
Untuk widget yang kompleks, akan ada operasi tertentu yang ingin Anda jalankan hanya sekali tidak peduli berapa kali konfigurasi berubah.
Atau mungkin ada beberapa operasi berat yang tidak perlu berjalan lebih dari sekali. Operasi tersebut akan menjadi bagian dari fungsi yang sesuai dengan load
properti dan bukan reload
properti .
Langkah 5: Memperbarui manifes ekstensi
vss-extension.json
Buka file untuk menyertakan dua entri baru ke array dalam contributions
properti . Satu untuk HelloWorldWidget3
widget dan yang lain untuk konfigurasinya.
Anda memerlukan gambar pratinjau lain untuk widget ketiga. Beri nama ini preview3.png
dan letakkan img
di folder .
Perbarui array dalam files
properti untuk menyertakan dua file HTML baru yang kami tambahkan dalam contoh ini.
{
...
"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
}
],
...
}
Kontribusi untuk konfigurasi widget mengikuti model yang sedikit berbeda dari widget itu sendiri. Entri kontribusi untuk konfigurasi widget memiliki:
- ID untuk mengidentifikasi kontribusi Anda. ID harus unik dalam ekstensi.
- Jenis kontribusi. Untuk semua konfigurasi widget, harus
ms.vss-dashboards-web.widget-configuration
- Array target tempat kontribusi berkontribusi. Untuk semua konfigurasi widget, ia memiliki satu entri:
ms.vss-dashboards-web.widget-configuration
. - Properti yang berisi sekumpulan properti yang menyertakan nama, deskripsi, dan URI file HTML yang digunakan untuk konfigurasi.
Untuk mendukung konfigurasi, kontribusi widget juga perlu diubah. Array target untuk widget perlu diperbarui untuk menyertakan ID untuk konfigurasi dalam formulir <publisher
>.>id for the extension
<.<id for the configuration contribution
> yang dalam hal ini adalah .fabrikam.vsts-extensions-myExtensions.HelloWorldWidget.Configuration
Peringatan
Jika entri kontribusi untuk widget yang dapat dikonfigurasi tidak menargetkan konfigurasi menggunakan penerbit dan nama ekstensi yang tepat seperti yang dijelaskan sebelumnya, tombol konfigurasi tidak muncul untuk widget.
Di akhir bagian ini, file manifes harus berisi tiga widget dan satu konfigurasi. Anda bisa mendapatkan manifes lengkap dari sampel di sini.
Langkah 6: Mengemas, menerbitkan, dan berbagi
Jika ekstensi Anda tidak diterbitkan, lihat bagian ini. Jika Anda sudah menerbitkan ekstensi, Anda dapat mengemas ulang ekstensi dan langsung memperbaruinya ke Marketplace.
Langkah 7: Tambahkan widget dari katalog
Sekarang, buka dasbor tim Anda di https://dev.azure.com/{Your_Organization}/{Your_Project}. Jika halaman ini sudah terbuka, refresh. Arahkan mouse ke Edit dan pilih Tambahkan. Tindakan ini harus membuka katalog widget tempat Anda menemukan widget yang Anda instal. Untuk menambahkan widget ke dasbor Anda, pilih widget Anda dan pilih Tambahkan.
Pesan yang mirip dengan yang berikut ini, meminta Anda untuk mengonfigurasi widget.
Ada dua cara untuk mengonfigurasi widget. Salah satunya adalah mengarahkan mouse ke widget, pilih elipsis yang muncul di sudut kanan atas lalu pilih Konfigurasikan. Yang lain adalah memilih tombol Edit di kanan bawah dasbor, lalu pilih tombol konfigurasi yang muncul di sudut kanan atas widget. Membuka pengalaman konfigurasi di sisi kanan, dan pratinjau widget Anda di tengah. Lanjutkan dan pilih kueri dari menu dropdown. Pratinjau langsung menunjukkan hasil yang diperbarui. Pilih Simpan dan widget Anda menampilkan hasil yang diperbarui.
Langkah 8: Mengonfigurasi lebih banyak (opsional)
Anda dapat menambahkan elemen formulir HTML sebanyak yang configuration.html
Anda butuhkan dalam untuk konfigurasi lainnya.
Ada dua fitur yang dapat dikonfigurasi yang tersedia di luar kotak: Nama widget dan ukuran widget.
Secara default, nama yang Anda berikan untuk widget Anda dalam manifes ekstensi disimpan sebagai nama widget untuk setiap instans widget Anda yang pernah ditambahkan ke dasbor.
Anda dapat mengizinkan pengguna untuk mengonfigurasi, sehingga mereka dapat menambahkan nama apa pun yang mereka inginkan ke instans widget Anda.
Untuk mengizinkan konfigurasi tersebut, tambahkan isNameConfigurable:true
di bagian properti untuk widget Anda dalam manifes ekstensi.
Jika Anda memberikan lebih dari satu entri untuk widget Anda dalam supportedSizes
array dalam manifes ekstensi, maka pengguna juga dapat mengonfigurasi ukuran widget.
Manifes ekstensi untuk sampel ketiga dalam panduan ini akan terlihat seperti contoh berikut jika kita mengaktifkan nama widget dan konfigurasi ukuran:
{
...
"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"]
}
},
...
]
}
Dengan perubahan sebelumnya, kemas ulang dan perbarui ekstensi Anda. Refresh dasbor yang memiliki widget ini (Halo Dunia Widget 3 (dengan konfigurasi)). Buka mode konfigurasi untuk widget Anda, Anda sekarang dapat melihat opsi untuk mengubah nama dan ukuran widget.
Pilih ukuran yang berbeda dari menu drop-down. Anda melihat pratinjau langsung diubah ukurannya. Simpan perubahan dan widget di dasbor juga diubah ukurannya.
Mengubah nama widget tidak mengakibatkan perubahan yang terlihat pada widget karena widget sampel kami tidak menampilkan nama widget di mana pun. Mari kita ubah kode sampel untuk menampilkan nama widget alih-alih teks "Halo Dunia" yang dikodekan secara permanen.
Untuk melakukannya, ganti teks yang dikodekan secara permanen "Halo Dunia" dengan widgetSettings.name
di baris tempat kita mengatur teks h2
elemen.
Tindakan ini memastikan bahwa nama widget ditampilkan setiap kali widget dimuat pada refresh halaman.
Karena kita ingin pratinjau langsung diperbarui setiap kali konfigurasi berubah, kita harus menambahkan kode yang sama di reload
bagian kode kita juga.
Pernyataan pengembalian akhir dalam hello-world3.html
adalah sebagai berikut:
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);
}
}
Kemas ulang dan perbarui ekstensi Anda lagi. Refresh dasbor yang memiliki widget ini.
Setiap perubahan pada nama widget, dalam mode konfigurasi, perbarui judul widget sekarang.