Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019
Les widgets d’un tableau de bord sont implémentés en tant que contributions dans l’infrastructure d’extension. Une seule extension peut avoir plusieurs contributions. Découvrez comment créer une extension avec plusieurs widgets en tant que contributions.
Cet article est divisé en trois parties, chacun construit sur le précédent. Vous commencez par un widget simple et vous terminez par un widget complet.
Conseil
Consultez notre documentation la plus récente sur le développement d’extensions à l’aide du Kit de développement logiciel (SDK) d’extension Azure DevOps.
Prérequis
Certaines connaissances de JavaScript, HTML et CSS sont requises pour le développement de widgets.
Une « organisation » dans Azure DevOps. Créez une organisation.
Éditeur de texte. Pour la plupart des tutoriels, nous utilisons Visual Studio Code.
CLI multiplateforme pour Azure DevOps (tfx-cli) pour empaqueter vos extensions.
- tfx-cli peut être installé à l’aide
npm
d’un composant de Node.js en exécutantnpm i -g tfx-cli
- tfx-cli peut être installé à l’aide
Répertoire de base de votre projet. Ce répertoire, appelé
home
tout au long du didacticiel, doit avoir la structure suivante après que vous ayez effectué les étapes décrites dans cet article :|--- 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
Dans ce didacticiel
- Partie 1 : Hello World : montre comment créer un widget, qui imprime un message Hello World simple.
- Partie 2 : Hello World avec l’API REST Azure DevOps : s’appuie sur la première partie en ajoutant un appel à une API REST Azure DevOps.
- Partie 3 : Configurer Hello World : explique comment ajouter une configuration à votre widget.
Remarque
Si vous êtes pressé et que vous souhaitez mettre votre main sur le code immédiatement, vous pouvez télécharger l’exemple d’extension pour Azure DevOps.
Une fois téléchargé, accédez au dossier widgets
, puis suivez directement les étapes 6 et 7 pour publier l'extension d'exemple qui contient trois widgets d'exemples de complexité diverse.
Commencez par découvrir quelques styles de base pour les widgets que nous fournissons prêts à l'emploi, ainsi que des conseils sur la structure des widgets.
Partie 1 : Hello World
La partie 1 présente un widget qui imprime Hello World à l’aide de JavaScript.
Étape 1 : Obtenir le Kit de développement logiciel (SDK) client
Le script du Kit de développement logiciel (SDK) principal, VSS.SDK.min.js
permet aux extensions web de communiquer avec le frame Azure DevOps hôte. Le script effectue des opérations telles que l’initialisation, la notification que l’extension est chargée ou l’obtention du contexte sur la page active.
Pour récupérer le Kit de développement logiciel (SDK), utilisez la npm install
commande suivante :
npm install vss-web-extension-sdk
Recherchez le fichier sdk VSS.SDK.min.js
client situé dans le vss-web-extension-sdk/lib
dossier, puis placez-le dans votre home/sdk/scripts
dossier.
Pour plus d’informations, consultez la page GitHub du SDK (Kit de Développement Logiciel) client.
Étape 2 : Configurer votre page HTML
Création d’un fichier appelé hello-world.html
. Votre page HTML est le ciment qui maintient votre mise en page ensemble et inclut des références à CSS et JavaScript. Vous pouvez nommer ce fichier n’importe quoi. Si vous utilisez un autre nom de fichier, mettez à jour toutes les références avec hello-world
le nom que vous utilisez.
Votre widget est basé sur HTML et est hébergé dans un iframe.
Copiez le code HTML suivant dans votre hello-world.html
fichier. Nous ajoutons la référence obligatoire au VSS.SDK.min.js
fichier et incluons un h2
élément, qui est mis à jour avec la chaîne Hello World à l’étape à venir.
<!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>
Même si vous utilisez un fichier HTML, la plupart des éléments principaux HTML autres que le script et le lien sont ignorés par l’infrastructure.
Étape 3 : Mettre à jour JavaScript
Nous utilisons JavaScript pour afficher le contenu dans le widget. Dans cet article, nous encapsulons tout notre code JavaScript à l’intérieur d’un élément <script>
dans le fichier HTML. Vous pouvez choisir d’avoir ce code dans un fichier JavaScript distinct et de le référencer dans le fichier HTML.
Le code restitue le contenu. Ce code JavaScript initialise également le Kit de développement logiciel (SDK) VSS, mappe le code de votre widget au nom de votre widget et avertit l’infrastructure d’extension des réussites ou des échecs du widget.
Dans ce cas, le code suivant imprime Hello World dans le widget. Ajoutez cet script
élément dans le head
de l'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
initialise la liaison entre l'iframe hébergeant le widget et la trame hôte.Transmettez
explicitNotifyLoaded: true
afin que le widget puisse avertir explicitement l’hôte lorsqu’il a terminé le chargement. Ce contrôle nous permet d’avertir l’achèvement du chargement après avoir vérifié que les modules dépendants sont chargés. UtilisezusePlatformStyles: true
ce qui permet au widget d’utiliser des styles principaux Azure DevOps pour les éléments HTML, tels quebody
etdiv
. Si vous ne souhaitez pas que le widget utilise ces styles, passezusePlatformStyles: false
.VSS.require
est utilisé pour charger les bibliothèques de scripts VSS requises. Un appel à cette méthode charge automatiquement les bibliothèques générales telles que JQuery et JQueryUI. Dans notre cas, nous dépendons de la bibliothèque WidgetHelpers, qui est utilisée pour communiquer l’état du widget à l’infrastructure du widget. Transmettez donc le nom du module correspondantTFS/Dashboards/WidgetHelpers
et une fonction de rappel àVSS.require
. Le rappel est appelé une fois le module chargé. Le rappel contient le reste du code JavaScript nécessaire pour le widget. À la fin du rappel, appelezVSS.notifyLoadSucceeded
pour notifier l’achèvement du chargement.WidgetHelpers.IncludeWidgetStyles
inclut une feuille de style avec un css de base pour vous aider à démarrer. Pour utiliser ces styles, encapsulez votre contenu à l’intérieur d’un élément HTML avec la classewidget
.VSS.register
est utilisé pour mapper une fonction en JavaScript, qui identifie de manière unique le widget parmi les différentes contributions de votre extension. Le nom doit correspondre auid
qui identifie votre contribution, comme décrit dans l'étape 5. Pour les widgets, la fonction transmiseVSS.register
doit retourner un objet qui satisfait auIWidget
contrat. Par exemple, l’objet retourné doit avoir une propriété de chargement dont la valeur est une autre fonction qui a la logique principale pour afficher le widget. Dans notre cas, il s’agit de mettre à jour le texte de l’élémenth2
sur Hello World. Il s’agit de cette fonction appelée lorsque l’infrastructure de widget instancie votre widget. Nous utilisons leWidgetStatusHelper
de WidgetHelpers pour renvoyer leWidgetStatus
comme une réussite.Avertissement
Si le nom utilisé pour inscrire le widget ne correspond pas à l’ID de la contribution dans le manifeste, le widget fonctionne de manière inattendue.
Étape 4 : Mettre à jour votre logo d’extension
Votre logo s’affiche dans la Place de marché et dans le catalogue de widgets une fois qu’un utilisateur installe votre extension.
Vous avez besoin d’une icône de catalogue de 98 x 98 pixels. Choisissez une image, nommez-la logo.png
et placez-la dans le img
dossier. Vous pouvez nommer l'image comme vous le souhaitez, à condition que le manifeste d'extension de l'étape suivante soit mis à jour avec le nom que vous utilisez.
Étape 5 : Créer votre manifeste d’extension
Chaque extension doit avoir un fichier manifeste d’extension. Créez un fichier json appelé vss-extension.json
dans le home
répertoire avec le contenu suivant :
{
"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
}
]
}
Le vss-extension.json
fichier doit toujours se trouver à la racine du répertoire de base. Pour tous les autres fichiers, vous pouvez les placer dans la structure souhaitée à l’intérieur du dossier. Veillez simplement à mettre à jour les références de manière appropriée dans les fichiers HTML et dans le manifeste vss-extension.json
.
Pour plus d'informations sur les attributs requis, veuillez consulter la référence du manifeste d'extension.
Remarque
Remplacez publisher
par le nom de votre éditeur. Pour créer un publieur, consultez Package/Publish/Install.
Icônes
La icons
strophe spécifie le chemin d’accès à l’icône de votre extension dans votre fichier de manifeste.
Contributions
Chaque entrée de contribution définit des propriétés.
Pour identifier votre contribution, utilisez
id
. Cet ID doit être unique au sein d’une extension. Cet ID doit correspondre au nom que vous avez utilisé à "l'étape 3" pour enregistrer votre widget.The
type
de contribution. Pour tous les widgets, le type doit êtrems.vss-dashboards-web.widget
.Le tableau
targets
auquel la contribution contribue. Pour tous les widgets, la cible doit être[ms.vss-dashboards-web.widget-catalog]
.properties
sont des objets qui incluent des propriétés pour le type de contribution. Pour les widgets, les propriétés suivantes sont obligatoires :Propriété Descriptif name
Nom du widget à afficher dans le catalogue de widgets. description
Description du widget à afficher dans le catalogue de widgets. catalogIconUrl
Chemin relatif de l’icône de catalogue que vous avez ajoutée à l’étape 4 pour qu'elle s'affiche dans le catalogue de widgets. L’image doit être de 98 x 98 pixels. Si vous avez utilisé une structure de dossiers différente ou un autre nom de fichier, spécifiez le chemin d’accès relatif approprié ici. previewImageUrl
Chemin relatif de l’image d’aperçu que vous avez ajoutée à l’étape 4 afin de l'afficher dans le catalogue de widgets. L’image doit être de 330 x 160 pixels. Si vous avez utilisé une structure de dossiers différente ou un autre nom de fichier, spécifiez le chemin d’accès relatif approprié ici. uri
Chemin relatif du fichier HTML que vous avez ajouté dans l’étape 1. Si vous avez utilisé une structure de dossiers différente ou un autre nom de fichier, spécifiez le chemin d’accès relatif approprié ici. supportedSizes
Tableau de tailles prises en charge par votre widget. Lorsqu’un widget prend en charge plusieurs tailles, la première taille du tableau est la taille par défaut du widget. widget size
est spécifié pour les lignes et les colonnes occupées par le widget dans la grille du tableau de bord. Une ligne/colonne correspond à 160 px. Toute dimension supérieure à 1x1 obtient un supplément de 10 px qui représentent la marge entre les widgets. Par exemple, un widget 3x2 est160*3+10*2
large et160*2+10*1
haut. La taille maximale prise en charge est 4x4.supportedScopes
Actuellement, seuls les tableaux de bord d’équipe sont pris en charge. La valeur doit être project_team
. Les futures mises à jour peuvent inclure d’autres options pour les étendues du tableau de bord.
Pour en savoir plus sur les points de contribution, consultez les points d’extensibilité.
Fichiers
La files
sanza indique les fichiers que vous souhaitez inclure dans votre package : votre page HTML, vos scripts, le script du Kit de développement logiciel (SDK) et votre logo.
Définissez addressable
sur true
sauf si vous incluez d’autres fichiers qui n’ont pas besoin d’être adressables par URL.
Remarque
Pour plus d’informations sur le fichier manifeste d’extension, comme ses propriétés et leur action, consultez la référence du manifeste d’extension.
Étape 6 : Empaqueter, publier et partager
Une fois que vous avez votre extension écrite, l’étape suivante pour l’obtenir dans la Place de marché consiste à empaqueter tous vos fichiers ensemble. Toutes les extensions sont empaquetées en tant que fichiers .vsix compatibles VSIX 2.0. Microsoft fournit une interface de ligne de commande multiplateforme (CLI) pour empaqueter votre extension.
Obtenir l’outil d’empaquetage
Vous pouvez installer ou mettre à jour tfx-cli à l’aide npm
d’un composant de Node.js, à partir de votre ligne de commande.
npm i -g tfx-cli
Empaqueter votre extension
L’empaquetage de votre extension dans un fichier .vsix est sans effort une fois que vous avez le tfx-cli. Accédez au répertoire de base de votre extension et exécutez la commande suivante.
tfx extension create --manifest-globs vss-extension.json
Remarque
Une version d’extension/d’intégration doit être incrémentée sur chaque mise à jour.
Lorsque vous mettez à jour une extension existante, mettez à jour la version dans le manifeste ou utilisez l'option de ligne de commande --rev-version
. Cela incrémente le numéro de version de correctif de votre extension et enregistre la nouvelle version dans votre manifeste.
Après avoir empaqueter votre extension dans un fichier .vsix, vous êtes prêt à publier votre extension sur la Place de marché.
Créer un serveur de publication pour l’extension
Toutes les extensions, y compris les extensions de Microsoft, sont identifiées comme étant fournies par un éditeur. Si vous n’êtes pas déjà membre d’un éditeur existant, créez-en un.
Connectez-vous au portail de publication visual Studio Marketplace.
Si vous n’êtes pas déjà membre d’un éditeur existant, vous devez créer un éditeur. Si vous avez déjà un éditeur, veuillez faire défiler jusqu'à Publier des extensions sous Sites connexes et sélectionner cette option.
- Spécifiez un identificateur pour votre éditeur, par exemple : mycompany-myteam.
- L’identificateur est utilisé comme valeur pour l’attribut
publisher
dans le fichier manifeste de vos extensions.
- L’identificateur est utilisé comme valeur pour l’attribut
- Spécifiez un nom complet pour votre éditeur, par exemple : Mon équipe.
- Spécifiez un identificateur pour votre éditeur, par exemple : mycompany-myteam.
Consultez le Contrat d’éditeur du Marketplace, puis sélectionnez Créer.
Votre éditeur est maintenant défini. Dans une version ultérieure, vous pouvez accorder des autorisations pour afficher et gérer les extensions de votre éditeur.
La publication d’extensions sous un éditeur commun simplifie le processus pour les équipes et les organisations, offrant une approche plus sécurisée. Cette méthode élimine la nécessité de distribuer un ensemble unique d’informations d’identification entre plusieurs utilisateurs, ce qui améliore la sécurité.
Mettez à jour le vss-extension.json
fichier manifeste dans les exemples pour remplacer l’ID d’éditeur factice fabrikam par votre ID d’éditeur.
Publier et partager l’extension
Vous pouvez maintenant charger votre extension sur la Place de marché.
Sélectionnez Charger une nouvelle extension, accédez à votre fichier .vsix empaqueté, puis sélectionnez Charger.
Vous pouvez également téléverser votre extension via la ligne de commande en utilisant la commande tfx extension publish
au lieu de tfx extension create
pour empaqueter et publier votre extension en une seule étape. Vous pouvez éventuellement utiliser --share-with
pour partager votre extension avec un ou plusieurs comptes après la publication. Vous avez également besoin d’un jeton d’accès personnel.
tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization
Étape 7 : Ajouter un widget à partir du catalogue
Connectez-vous à votre projet,
http://dev.azure.com/{Your_Organization}/{Your_Project}
.Veuillez sélectionner Aperçu des >tableaux de bord.
Sélectionnez Ajouter un widget.
Sélectionnez votre widget, puis choisissez Ajouter.
Le widget s’affiche sur votre tableau de bord.
Partie 2 : Hello World avec l’API REST Azure DevOps
Les widgets peuvent appeler n’importe quelle API REST dans Azure DevOps pour interagir avec les ressources Azure DevOps.
Dans l’exemple suivant, nous utilisons l’API REST pour WorkItemTracking pour extraire des informations sur une requête existante et afficher des informations de requête dans le widget sous le texte Hello World .
Étape 1 : Ajouter un fichier HTML
Copiez le fichier hello-world.html
de l’exemple précédent, puis renommez la copie en hello-world2.html
. Votre dossier ressemble maintenant à l’exemple suivant :
|--- README.md
|--- node_modules
|--- SDK
|--- scripts
|--- VSS.SDK.min.js
|--- img
|--- logo.png
|--- scripts
|--- hello-world.html // html page to be used for your widget
|--- hello-world2.html // renamed copy of hello-world.html
|--- vss-extension.json // extension's manifest
Pour conserver les informations relatives à la requête, veuillez ajouter un nouvel élément div
sous l'élément h2
.
Mettez à jour le nom du widget de HelloWorldWidget
à HelloWorldWidget2
dans la ligne où vous appelez VSS.register
.
Cette action permet au framework d’identifier de manière unique le widget dans l’extension.
<!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>
Étape 2 : Accéder aux ressources Azure DevOps
Pour activer l’accès aux ressources Azure DevOps, les scopes doivent être spécifiés dans le manifeste de l’extension. Nous ajoutons le champ vso.work
à notre manifeste. Cette étendue indique que le widget a besoin d’un accès en lecture seule aux requêtes et aux éléments de travail. Pour afficher toutes les étendues disponibles, consultez Étendues.
Ajoutez le code suivant à la fin de votre manifeste d’extension :
{
"scopes":[
"vso.work"
]
}
Pour inclure d’autres propriétés, vous devez les répertorier explicitement, par exemple :
{
"name": "example-widget",
"publisher": "example-publisher",
"version": "1.0.0",
"scopes": [
"vso.work"
]
}
Avertissement
L’ajout ou la modification d’étendues après la publication d’une extension n’est actuellement pas pris en charge. Si vous avez déjà chargé votre extension, supprimez-la de la Place de marché. Accédez au portail de publication visual Studio Marketplace, sélectionnez avec le bouton droit votre extension, puis sélectionnez Supprimer.
Étape 3 : Appeler l’API REST
Il existe de nombreuses bibliothèques côté client accessibles via le KIT de développement logiciel (SDK) pour effectuer des appels d’API REST dans Azure DevOps. Ces bibliothèques sont appelées clients REST et sont des wrappers JavaScript autour des appels Ajax pour tous les points de terminaison côté serveur disponibles. Vous pouvez utiliser des méthodes fournies par ces clients au lieu d’écrire vous-même des appels Ajax. Ces méthodes mappent les réponses d’API aux objets que votre code peut consommer.
Dans cette étape, veuillez mettre à jour l'appel VSS.require
pour charger AzureDevOps/WorkItemTracking/RestClient
, qui fournit le client REST WorkItemTracking. Vous pouvez utiliser ce client REST pour obtenir des informations sur une requête appelée Feedback
sous le dossier Shared Queries
.
À l'intérieur de la fonction que vous passez à VSS.register
, créez une variable pour contenir l'ID du projet actuel. Vous avez besoin de cette variable pour extraire la requête. Créez également une méthode getQueryInfo
pour utiliser le client REST. Cette méthode est ensuite appelée à partir de la méthode de chargement.
La méthode getClient
fournit une instance du client REST dont vous avez besoin. La méthode getQuery
retourne la requête encapsulée dans une promesse.
La mise à jour VSS.require
se présente comme suit :
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();
});
Notez l’utilisation de la méthode Failure de WidgetStatusHelper
. Il vous permet d’indiquer à l’infrastructure de widget qu’une erreur s’est produite et tirer parti de l’expérience d’erreur standard fournie à tous les widgets.
Si vous n’avez pas la Feedback
requête sous le dossier Shared Queries
, remplacez Shared Queries\Feedback
dans le code par le chemin d’accès d’une requête qui existe dans votre projet.
Étape 4 : Afficher la réponse
La dernière étape consiste à afficher les informations de requête à l’intérieur du widget. La fonction getQuery
retourne un objet de type Contracts.QueryHierarchyItem
à l'intérieur d'une promesse. Dans cet exemple, vous affichez l’ID de requête, le nom de la requête et le nom du créateur de requête sous le texte Hello World .
Remplacez le commentaire // Do something with the query
par le code suivant :
// 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);
Votre hello-world2.html
final ressemble à l'exemple suivant :
<!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>
Étape 5 : Mettre à jour le manifeste d’extension
Dans cette étape, nous mettons à jour le manifeste d’extension pour inclure une entrée pour notre deuxième widget.
Ajoutez une nouvelle contribution au tableau dans la propriété , et ajoutez le nouveau fichier au tableau dans la propriété .
Vous avez besoin d’une autre image d’aperçu pour le deuxième widget. Nommez ceci preview2.png
et placez-le dans le dossier img
.
{
...,
"contributions": [
...,
{
"id": "HelloWorldWidget2",
"type": "ms.vss-dashboards-web.widget",
"targets": [
"ms.vss-dashboards-web.widget-catalog"
],
"properties": {
"name": "Hello World Widget 2 (with API)",
"description": "My second widget",
"previewImageUrl": "img/preview2.png",
"uri": "hello-world2.html",
"supportedSizes": [
{
"rowSpan": 1,
"columnSpan": 2
}
],
"supportedScopes": ["project_team"]
}
}
],
"files": [
{
"path": "hello-world.html",
"addressable": true
},
{
"path": "hello-world2.html",
"addressable": true
},
{
"path": "sdk/scripts",
"addressable": true
},
{
"path": "img",
"addressable": true
}
],
"scopes": [
"vso.work"
]
}
Étape 6 : Empaqueter, publier et partager
Créez un package, publiez et partagez votre extension. Si vous avez déjà publié l’extension, vous pouvez repackager l’extension et la mettre directement à jour sur la Place de marché.
Étape 7 : Ajouter un widget à partir du catalogue
Accédez maintenant au tableau de bord de votre équipe à l’adresse https:\//dev.azure.com/{Your_Organization}/{Your_Project}
. Si cette page est déjà ouverte, actualisez-la.
Pointez sur Modifier et sélectionnez Ajouter. Le catalogue de widgets s’ouvre là où vous trouvez le widget que vous avez installé.
Pour l’ajouter à votre tableau de bord, choisissez votre widget, puis sélectionnez Ajouter.
Partie 3 : Configurer Hello World
Dans la partie 2 de ce guide, vous avez vu comment créer un widget qui affiche les informations de requête pour une requête à code fixe. Dans cette partie, vous ajoutez la possibilité de configurer la requête à utiliser au lieu de la requête codée en dur. En mode de configuration, l’utilisateur peut voir un aperçu en direct du widget en fonction de ses modifications. Ces modifications sont enregistrées dans le widget du tableau de bord lorsque l’utilisateur sélectionne Enregistrer.
Étape 1 : Ajouter un fichier HTML
Les implémentations de widgets et de configurations de widgets sont beaucoup plus similaires. Les deux sont implémentés dans l’infrastructure d’extension en tant que contributions. Les deux utilisent le même fichier SDK, VSS.SDK.min.js
. Les deux sont basés sur HTML, JavaScript et CSS.
Copiez le fichier html-world2.html
de l’exemple précédent et renommez la copie en hello-world3.html
. Ajoutez un autre fichier HTML nommé configuration.html
.
Votre dossier ressemble maintenant à l’exemple suivant :
|--- 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
Ajoutez le code HTML suivant dans configuration.html
. Vous ajoutez essentiellement la référence obligatoire au VSS.SDK.min.js
fichier et un select
élément pour la liste déroulante pour sélectionner une requête dans une liste prédéfinie.
<!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>
Étape 2 : Configurer JavaScript
Utilisez JavaScript pour afficher le contenu dans la configuration du widget, comme nous l’avons fait pour le widget à l’étape 3 de la partie 1 de ce guide. Ce code JavaScript restitue le contenu, initialise le SDK VSS, mappe le code de la configuration de votre widget au nom de configuration et transmet les paramètres de configuration à l’infrastructure. Dans notre cas, le code suivant charge la configuration du widget.
Veuillez ouvrir le fichier configuration.html
et l'élément suivant <script>
dans le fichier <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
etVSS.register
jouent le même rôle que celui qu'ils jouaient pour le widget, comme décrit dans la partie 1. La seule différence est que pour les configurations de widget, la fonction passée àVSS.register
doit retourner un objet qui répond auIWidgetConfiguration
contrat.La
load
propriété duIWidgetConfiguration
contrat doit avoir une fonction comme valeur. Cette fonction comporte l’ensemble des étapes permettant d’afficher la configuration du widget. Dans notre cas, il s’agit de mettre à jour la valeur sélectionnée de l’élément de liste déroulante avec les paramètres existants, le cas échéant. Cette fonction est appelée lorsque l’infrastructure instancie votrewidget configuration
La
onSave
propriété duIWidgetConfiguration
contrat doit avoir une fonction comme valeur. Cette fonction est appelée par l’infrastructure lorsque l’utilisateur sélectionne Enregistrer dans le volet de configuration. Si l’entrée utilisateur est prête à être enregistrée, sérialisez-la dans une chaîne, formez l’objetcustom settings
et utilisez-laWidgetConfigurationSave.Valid()
pour enregistrer l’entrée utilisateur.
Dans ce guide, nous utilisons JSON pour sérialiser l’entrée utilisateur dans une chaîne. Vous pouvez choisir n’importe quelle autre façon de sérialiser l’entrée utilisateur en chaîne de caractères.
Il est accessible au widget via la propriété customSettings de l’objet WidgetSettings
.
Le widget doit être désérialisé, ce qui est décrit à l'étape 4.
Étape 3 : Activer la préversion en direct - JavaScript
Pour activer la mise à jour en préversion en direct lorsque l’utilisateur sélectionne une requête dans la liste déroulante, attachez un gestionnaire d’événements de modification au bouton. Ce gestionnaire avertit l’infrastructure que la configuration a changé.
Il transmet également le customSettings
à utiliser pour mettre à jour la préversion. Pour notifier le cadre, la méthode notify
sur le widgetConfigurationContext
doit être appelée. Il prend deux paramètres, le nom de l’événement, qui est WidgetHelpers.WidgetEvent.ConfigurationChange
dans ce cas, et un EventArgs
objet pour l’événement, créé à partir de avec customSettings
l’aide de la méthode d’assistance WidgetEvent.Args
.
Ajoutez le code suivant dans la fonction attribuée à la propriété load
.
$queryDropdown.on("change", function () {
var customSettings = {
data: JSON.stringify({
queryPath: $queryDropdown.val()
})
};
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
widgetConfigurationContext.notify(eventName, eventArgs);
});
Vérifiez que l’infrastructure est avertie de la modification de configuration au moins une fois pour activer le bouton Enregistrer .
À la fin, votre configuration.html
ressemble à l'exemple suivant :
<!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>
Étape 4 : Implémenter le rechargement dans le widget - JavaScript
Configurez la configuration du widget pour stocker le chemin de requête sélectionné par l’utilisateur.
Vous devez maintenant mettre à jour le code dans le widget pour utiliser cette configuration stockée au lieu du code codé en dur Shared Queries/Feedback
de l'exemple précédent.
Ouvrez le fichier hello-world3.html
et mettez à jour le nom du widget de HelloWorldWidget2
à HelloWorldWidget3
dans la ligne où vous appelez VSS.register
.
Cette action permet au framework d’identifier de manière unique le widget dans l’extension.
La fonction mappée à HelloWorldWidget3
via VSS.register
retourne actuellement un objet qui satisfait le contrat IWidget
.
Étant donné que notre widget a maintenant besoin d’une configuration, cette fonction doit être mise à jour afin de retourner un objet qui satisfait le IConfigurableWidget
contrat.
Pour ce faire, mettez à jour l’instruction return pour inclure une propriété appelée rechargement conformément au code suivant. La valeur de cette propriété est une fonction qui appelle la getQueryInfo
méthode une fois de plus.
Cette méthode de rechargement est appelée par le framework chaque fois que l’entrée utilisateur change pour afficher l’aperçu en direct. Cette méthode de rechargement est également appelée lorsque la configuration est enregistrée.
return {
load: function (widgetSettings) {
// Set your title
var $title = $('h2.title');
$title.text('Hello World');
return getQueryInfo(widgetSettings);
},
reload: function (widgetSettings) {
return getQueryInfo(widgetSettings);
}
}
Le chemin de requête intégré en dur dans getQueryInfo
doit être remplacé par le chemin de requête configuré, qui peut être extrait du paramètre widgetSettings
passé à la méthode.
Ajoutez le code suivant tout au début de la méthode getQueryInfo
et remplacez le chemin de requête codé en dur par 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();
}
À ce stade, votre widget est prêt à être affiché avec les paramètres configurés.
Les propriétés load
et reload
ont une fonction similaire. C’est le cas pour la plupart des widgets simples.
Pour les widgets complexes, il existe certaines opérations que vous souhaitez exécuter une seule fois, peu importe le nombre de fois où la configuration change.
Ou il peut y avoir des opérations lourdes qui n’ont pas besoin d’être exécutées plus d’une fois. Ces opérations font partie de la fonction correspondant à la load
propriété et non à la reload
propriété.
Étape 5 : Mettre à jour le manifeste d’extension
Ouvrez le vss-extension.json
fichier pour inclure deux nouvelles entrées dans le tableau dans la contributions
propriété : l’une pour le HelloWorldWidget3
widget et l’autre pour sa configuration.
Vous avez besoin d’une autre image d’aperçu pour le troisième widget. Nommez ceci preview3.png
et placez-le dans le dossier img
.
Mettez à jour le tableau dans la files
propriété pour inclure les deux nouveaux fichiers HTML que vous avez ajoutés dans cet exemple.
{
...
"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
}
],
...
}
La contribution pour la configuration du widget suit un modèle légèrement différent du widget lui-même. Une entrée de contribution pour la configuration du widget a les éléments suivants :
- Pour identifier votre contribution, utilisez
id
. L’ID doit être unique dans une extension. - The
type
de contribution. Pour toutes les configurations de widget, il doit êtrems.vss-dashboards-web.widget-configuration
. - Le tableau
targets
auquel la contribution contribue. Pour toutes les configurations de widget, il a une entrée unique :ms.vss-dashboards-web.widget-configuration
. -
properties
Qui contient un ensemble de propriétés incluant le nom, la description et l’URI du fichier HTML utilisé pour la configuration.
Afin de permettre la configuration, il est également nécessaire de modifier la contribution du widget. Le tableau du targets
widget doit être mis à jour pour inclure l’ID de la configuration sous la forme suivante :
<publisher>.<id for the extension>.<id for the configuration contribution>
Dans ce cas, l’exemple est :
fabrikam.vsts-extensions-myExtensions.HelloWorldWidget.Configuration
Avertissement
Si l’entrée de contribution pour votre widget configurable ne cible pas la configuration à l’aide de l’éditeur et du nom d’extension appropriés, comme décrit précédemment, le bouton Configurer n’apparaît pas pour le widget.
À la fin de cette partie, le fichier manifeste doit contenir trois widgets et une configuration. Pour obtenir l’exemple de fichier manifeste complet, consultez vss-extension.json.
Étape 6 : Empaqueter, publier et partager
Si votre extension n’est pas publiée, consultez l’étape 6 : Package, publication et partage. Si vous avez déjà publié l’extension, vous pouvez repackager l’extension et la mettre directement à jour sur la Place de marché.
Étape 7 : Ajouter un widget à partir du catalogue
Accédez maintenant au tableau de bord de votre équipe à l’adresse https://dev.azure.com/{Your_Organization}/{Your_Project}
. Si cette page est déjà ouverte, actualisez-la.
Pointez sur Modifier et sélectionnez Ajouter. Cette action doit ouvrir le catalogue de widgets où vous trouvez le widget que vous avez installé.
Pour ajouter le widget à votre tableau de bord, choisissez votre widget, puis sélectionnez Ajouter.
Un message similaire à ce qui suit vous demande de configurer le widget.
Il existe deux façons de configurer des widgets. L’un consiste à passer la souris sur le widget, à sélectionner les trois points qui s’affichent dans le coin supérieur droit, puis à sélectionner Configurer. L’autre consiste à sélectionner le bouton Modifier en bas à droite du tableau de bord, puis à sélectionner le bouton Configurer qui apparaît en haut à droite du widget. Ouvre l’expérience de configuration sur le côté droit et un aperçu de votre widget au centre.
Choisissez une requête dans la liste déroulante. L’aperçu en direct affiche les résultats mis à jour. Sélectionnez Enregistrer et votre widget affiche les résultats mis à jour.
Étape 8 : Configurer plus (facultatif)
Vous pouvez ajouter autant d’éléments de formulaire HTML que nécessaire dans le configuration.html
pour des configurations supplémentaires.
Il existe deux fonctionnalités configurables disponibles prêtes à l’emploi : le nom du widget et la taille du widget.
Par défaut, le nom que vous fournissez pour votre widget dans le manifeste d’extension est stocké en tant que nom de widget pour chaque instance de votre widget qui est ajoutée à un tableau de bord.
Vous pouvez autoriser les utilisateurs à configurer afin qu’ils puissent ajouter n’importe quel nom qu’ils souhaitent à leur instance de votre widget.
Pour autoriser une telle configuration, ajoutez isNameConfigurable:true
dans la section propriétés de votre widget dans le manifeste de l’extension.
Si vous fournissez plusieurs entrées pour votre widget dans le supportedSizes
tableau du manifeste d’extension, les utilisateurs peuvent également configurer la taille du widget.
Le manifeste d’extension pour le troisième exemple de ce guide ressemble à l’exemple suivant si vous activez le nom et la configuration de taille du widget :
{
...
"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"]
}
},
...
]
}
Repackager et mettre à jour votre extension. Actualisez le tableau de bord contenant ce widget (Hello World Widget 3 (avec configuration)). Ouvrez le mode de configuration de votre widget. Vous devriez maintenant être en mesure de voir l’option permettant de modifier le nom et la taille du widget.
Choisissez une autre taille dans la liste déroulante. Vous voyez que l’aperçu en direct est redimensionné. Enregistrez la modification et le widget du tableau de bord est également redimensionné.
La modification du nom du widget n’entraîne aucune modification visible dans le widget, car nos exemples de widgets n’affichent pas le nom du widget n’importe où.
Modifiez l’exemple de code pour afficher le nom du widget au lieu du texte codé en dur Hello World en remplaçant le texte codé en dur Hello WorldwidgetSettings.name
par la ligne dans laquelle vous définissez le texte de l’élément h2
.
Cette action garantit que le nom du widget s’affiche chaque fois que le widget est chargé lors de l’actualisation de la page.
Étant donné que vous souhaitez que l’aperçu en direct soit mis à jour chaque fois que la configuration change, vous devez également ajouter le même code dans la reload
partie de votre code.
L'instruction return finale dans hello-world3.html
est la suivante :
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);
}
}
Veuillez reconditionner et mettre à jour votre extension. Actualisez le tableau de bord contenant ce widget.
Toute modification apportée au nom du widget, en mode de configuration, met à jour le titre du widget maintenant.