Bagikan melalui


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 menjalankan npm i -g tfx-cli
  • 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

  1. Bagian 1: Menunjukkan kepada Anda cara membuat widget baru, yang mencetak pesan "Halo Dunia" sederhana.
  2. Bagian 2: Dibangun pada bagian pertama dengan menambahkan panggilan ke REST API Azure DevOps.
  3. 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.

Cuplikan layar dasbor Gambaran Umum dengan widget sampel.

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 &lt;script&gt; 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 meneruskan usePlatformStyles: 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 meneruskan usePlatformStyles: 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 nama TFS/Dashboards/WidgetHelpers modul yang sesuai dan panggilan balik ke VSS.require. Panggilan balik dipanggil setelah modul dimuat. Panggilan balik memiliki sisa kode JavaScript yang diperlukan untuk widget. Di akhir panggilan balik, kami memanggil VSS.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 kelas widget.
  • VSS.register digunakan untuk memetakan fungsi di JavaScript, yang secara unik mengidentifikasi widget di antara berbagai kontribusi dalam ekstensi Anda. Nama harus cocok dengan id yang mengidentifikasi kontribusi Anda seperti yang dijelaskan di Langkah 5. Untuk widget, fungsi yang diteruskan harus VSS.register mengembalikan objek yang memenuhi IWidget 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 teks h2 elemen ke "Halo Dunia." Fungsi inilah yang dipanggil ketika kerangka kerja widget membuat instans widget Anda. Kami menggunakan WidgetStatusHelper dari WidgetHelpers untuk mengembalikan sebagai sukses WidgetStatus .

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 dalam vss-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) di home 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.

  1. Masuk ke Portal Penerbitan Marketplace Visual Studio
  2. 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.
    • Tentukan nama tampilan untuk penerbit Anda, misalnya: My Team
  3. 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

  1. Masuk ke proyek Anda, http://dev.azure.com/{Your_Organization}/{Your_Project}.

  2. Pilih Dasbor Gambaran Umum>.

  3. Pilih Tambahkan widget.

  4. 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".

Cuplikan layar dasbor Gambaran Umum dengan widget sampel menggunakan REST API untuk WorkItemTracking.

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

Cuplikan layar pratinjau langsung dasbor Gambaran Umum widget berdasarkan perubahan.

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, dan VSS.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 ke VSS.register harus mengembalikan objek yang memenuhi IWidgetConfiguration 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 instans widget 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, bentuk custom settings objek dan gunakan WidgetConfigurationSave.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.

Cuplikan layar dasbor Gambaran Umum dengan widget sampel dari katalog.

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.

Cuplikan layar memperlihatkan Widget tempat nama dan ukuran dapat dikonfigurasi.

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.