Archives de catégorie : Lightning Web Component

Le Jeu (2/2) : Afficher le déroulement de la compétition des voitures d’une course fictive

L’objectif du projet était de simuler une ‘course’ pour des voitures su un même trajet, mais roulant à des dates différentes.

Attaquons-nous à la dernière étape : la course !

1.         La définition de la course

Si les voitures ne partent pas à la même heure, on doit pouvoir trouver comment comparer leur avancée dans la course par rapport à leur date de départ.

Une course dans notre jeu sera d’aller d’une place à l’autre le plus vite possible.

On va créer un objet Car Race qui mémorise :

  • le nom de la course
  • le point de départ
  • le point d’arrivée

Et pour chaque participant, un objet Racer qui va mémoriser

  • la course
  • la voiture
  • la date/heure de début
  • la date/heure de fin
  • la position enregistrée de début (car status)
  • la position enregistrée de fin (car status)

Voici la configuration des deux objets dans l’Object Manager :

2.         Afficher la compétition

Maintenant nous pouvons comparer le parcours complet des participants même s’ils partent à des dates différentes. On va afficher avec un composant mis sur l’objet Course la position des participants à x minutes, x étant saisi par l’utilisateur (10’ après le départ fictif, 20’ après le départ, etc.).

a)              Le service coté serveur

On a besoin d’un code Apex qui va calculer la position des participants après x minutes de course.

public class CarRaceController {

@AuraEnabled(Cacheable=true)
public static Car_Status__c[] getRacePositions(ID raceID, Integer chronoInMinutes) {
// on retrouve la liste des participants
List<Racer__c> lRacers = [
SELECT
Id,
Car_Race__c,
Car__c,
Start_Date__c
FROM Racer__c
where Car_Race__c =:raceID
];

// le tableau où on stocke les position qu'on a trouvées.
List<Car_Status__c> knowPositions = new List<Car_Status__c>(); 

// pour chaque participant, on cherche sa dernière position à cette minute de la course
for (Racer__c racer : lRacers) {
// calcule l'heure pour se participant
DateTime positionTime =  racer.Start_Date__c;
positionTime = positionTime.addMinutes(chronoInMinutes);
// recherche la dernière position connue pour cette heure
List<Car_Status__c> carPosition = [
SELECT
Id,
Location__Latitude__s,
Location__Longitude__s,
Requested_On__c,
Car__c,
Car__r.Name
FROM Car_Status__c
WHERE Car__c = :racer.Car__c
AND Requested_On__c >= :racer.Start_Date__c
AND Requested_On__c <= :positionTime
ORDER BY Requested_On__c DESC
LIMIT 1
];

// si on a trouvé une position, on la met de coté
if (carPosition.size()>0) {
knowPositions.add(carPosition[0]);
}
}

// on renvoie les positions qu'on a trouvée
return knowPositions;
}

}

b)              Le composant

Comme d’habitude on dit où il doit s’afficher : sur les pages des objets Courses (Car Race).

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="RaceCarPositionsMap">

<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>

<targets>
<target>lightning__RecordPage</target>
</targets>

<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Car_Race__c</object>
</objects>

</targetConfig>
</targetConfigs>

</LightningComponentBundle>

La partie Html est un peu plus compliquée : elle a un champ inputMinutes pour saisir le nombre de minutes que l’on veut. Quand ce champ est modifié avec la valeur x, le code javascript minutesChangeHandler est appelé pour demander à Salesforce les positions à x minutes. La carte fonctionne sur le même mode que celle qu’on avait faite dans la partie précédente : elle affiche les marqueurs mapMarkers.

<template>
<article class="slds-card">

<div class="slds-m-around_medium">
<p>Race Id at {recordId}</p>
<p>Race Info of {raceName}</p>
<p>Position at {currentRaceMinutes}</p>
</div>

<lightning-input
name="inputMinutes" label="Minutes"
type="number"
value={currentRaceMinutes}
step="5" max="1000" min="0"
onchange={minutesChangeHandler}>
</lightning-input>

<div class="slds-m-around_medium">
<lightning-map
map-markers={mapMarkers}
zoom-level="11"
markers-title="Positions"
>
</lightning-map>
</div>
</article>
</template>

Le code Java script est fait sur le même modèle que le précédent, et va charger les positions des voitures à x minutes en appelant le code Apex getRacePositions avec l’id de la course et le nombre de minutes après le départ.

On fait le mapping deux fois :

  • une fois quand la page se charge
@wire(getRacePositions, { raceID :  '$recordId',  chronoInMinutes : '$currentRaceMinutes'  })
  • et une fois quand les minutes sont changées.
getRacePositions( { raceID :  this.recordId,  chronoInMinutes : this.currentRaceMinutes})

Le code pour créer les marqueurs ressemble à celui du composant précédent

this.mapMarkers = result.data.map(carPosition => {
const CarName = carPosition.Car__r.Name;
const Latitude = carPosition.Location__Latitude__s;
const Longitude = carPosition.Location__Longitude__s;

return {
location: { Latitude, Longitude },
title: CarName,
description: 'Coords: ${Latitude}, ${Longitude}',
icon: 'utility:animal_and_nature'
};

});

Voici le code complet javascript :

import { LightningElement, api, wire, track } from 'lwc';
import { getRecord , getFieldValue  } from 'lightning/uiRecordApi';
import getRacePositions from '@salesforce/apex/CarRaceController.getRacePositions';
import RACE_NAME from '@salesforce/schema/Car_Race__c.Name';
const raceFields = [
RACE_NAME
];

export default class RaceCarPositionsMap extends LightningElement {
@api recordId;
@wire(getRecord, { recordId: '$recordId', fields: raceFields })
raceInformation;

// les minutes où on se trouve (30 pour le test)
@track currentRaceMinutes = 0;

// les marqueurs pour la carte
@track mapMarkers = [];

 // les positions
@track carsPositions;

get raceName() {
return getFieldValue(this.raceInformation.data, RACE_NAME);
}

@wire(getRacePositions, { raceID :  '$recordId',  chronoInMinutes : '$currentRaceMinutes'  })
loadCar(result) {
if (result.data) {
this.carsPositions = result.data;
this.mapMarkers = result.data.map(carPosition => {
const CarName = carPosition.Car__r.Name;
const Latitude = carPosition.Location__Latitude__s;
const Longitude = carPosition.Location__Longitude__s;
return {
location: { Latitude, Longitude },
title: CarName,
description: 'Coords: ${Latitude}, ${Longitude}',
icon: 'utility:animal_and_nature'
};
});
}
}

minutesChangeHandler(event) {
this.currentRaceMinutes = event.target.value;
this.refreshMapForNewMinutes();
}

refreshMapForNewMinutes() {
getRacePositions( { raceID :  this.recordId,  chronoInMinutes : this.currentRaceMinutes})
.then(result => {
if (result.data) {
this.carsPositions = result.data;
this.mapMarkers = result.data.map(carPosition => {
const CarName = carPosition.Car__r.Name;
const Latitude = carPosition.Location__Latitude__s;
const Longitude = carPosition.Location__Longitude__s;
return {
location: { Latitude, Longitude },
title: CarName,
description: 'Coords: ${Latitude}, ${Longitude}',
icon: 'utility:animal_and_nature'
};
});
}
})
.catch(error => {
alert('Error '+JSON.stringify(error));
this.checkIfTimeEntryCanBeCreated();
});
}
}

 

c)              Le résultat

Une fois le composant installé dans la page des courses, voici ce que cela donne pour différentes minutes de course (85’, 90’).

Maintenant si on fait bouger les minutes, on voit les marqueurs des voitures se déplacer ! C’était l’objectif de cette partie ‘course virtuelle’ !

B.        Création de l’application Car Races

1.         Configuration

Pour accéder facilement à tous les écrans et objets de notre jeu, on peut créer « une application ».

Cela permet aux utilisateurs d’arriver plus facilement aux écrans concernant les voitures, la connexion, les courses.

Dans le menu Setup on choisit : App / App Manager puis on clique « New Lightning App ». On lui donne un nom et on choisit ce qu’elle doit afficher.

2.         Utilisation

Pour aller dans la nouvelle application, on clique en haut à gauche sur l’icône avec les neuf petits carrés, on choisit « Car Races » …

… et quand on est dans l’application, on ne voit dans la barre d’onglets que les objets configurés. C’est plus facile pour s’y retrouver.

Par exemple pour l’accès direct à la liste des voitures

Ou voir la carte des voitures avec leurs dernières positions enregistrées sur la home page

Ou encore … … voir une course !

 

Le Jeu (1/2) : Afficher la position des voitures en temps réel

Pour cette première partie du jeu, on va créer un composant qui va afficher dans une page Salesforce toutes les voitures sur une carte. A chaque fois qu’on regarde la carte, on voit si la voiture a bougé.

Pour cela je me suis inspiré du code de l’application « Ours » du cours Salesforce qui affichait une carte des Ours d’un Parc Naturel.

2.         Le composant

Comme avant, on doit faire un fichier de description pour dire où le composant s’affiche

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="CarInfo">
<apiVersion>45.0</apiVersion>

<isExposed>true</isExposed>

<targets>
<target>lightning__RecordPage</target>
</targets>

<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Car__c</object>
</objects>
</targetConfig>
</targetConfigs>

</LightningComponentBundle>

Le code HTML du composant est simple car il y a dans salesforce un composant tout prêt : lightning-map, à qui on donne une liste d’objet à placer sur la carte : mapMarkers.

<template>

<article class="slds-card">
<lightning-map
map-markers={mapMarkers}
zoom-level="11"
markers-title="Cars">
</lightning-map>
</article>

</template>

Le code javascript du composant va juste

  • charger les voitures depuis salesforce en appelant un code Apex : getAllCars
  • transformer les voitures en marqueurs pour la carte : data.map
import { LightningElement, track, wire } from 'lwc';
import getAllCars from '@salesforce/apex/CarController.getAllCars';

export default class CarMap extends LightningElement {

@track mapMarkers = [];
@track cars;

@wire(getAllCars, {})
loadCars(result) {
if (result.data) {
this.cars = result.data;
this.mapMarkers = result.data.map(car => {
const Latitude = car.Last_Position__Latitude__s;
const Longitude = car.Last_Position__Longitude__s;
return {
location: { Latitude, Longitude },
title: car.Name,
description: 'Coords: ${Latitude}, ${Longitude}',
icon: 'utility:animal_and_nature'
};
});
}

}}

Le code APEX qui renvoie les voitures est juste une requête SOQL vers la base Salesforce pour savoir la dernière position des voitures.

@AuraEnabled(Cacheable=true)

public static Car__c[] getAllCars() {
return [SELECT Id, Name,
Last_Position__longitude__s, Last_Position__latitude__s
FROM Car__c
WHERE Last_Position__longitude__s!= null
AND Last_Position__latitude__s != null
ORDER BY Name LIMIT 50
];
}
}

3.         Le résultat

Et voici ce que donne ce composant une fois installé dans une page Salesforce :

On sait où sont les voitures au fur et à mesure que salesforce récupère les informations depuis le serveur Cloud Mercedes !

 

Le module de gestion de la connexion de Salesforce vers Mercedes Cloud (2/3) : La connexion

Dans les Posts précédents, nous avons examiné comment appeler le serveur Mercedes Cloud ‘à la main’ dans la console de programmation Salesforce. Le but de ce Post est d’expliquer comment implémenter le code de manière à ce qu’il soit utilisable par un utilisateur normal.

1.         Un nouvel objet pour stocker les infos de connexion

On vient de travailler ‘à la main’ dans la console. Mais si on veut que ce soit facile de travailler avec tous ces codes, ce serait bien de les enregistrer quelque part.

Pour cela on va créer un objet SF qui sert à mémoriser les informations de la connexion vers Mercedes, on a besoin de :

  • client id =txt
  • client secret=txt
  • authorisation code=txt
  • access token=txt
  • expiration date = date/time
  • scope = texte
  • refresh token = texte

On va créer les champs de cet objet connexion avec le menu setup, comme on avait fait pour l’objet voiture.

On peut du coup saisir les informations de connexion dans Salesforce

Et aussi faire les requêtes avec du code SOQL comme on l’a fait avant pour les voitures :

SELECT Id, Mercedes_API_Client_ID__c, Mercedes_API_Client_Secret__c FROM Mercedes_API_Connection__c

2.         Comment savoir pour quelle connexion on a demandé l’autorisation ?

Quand le serveur Mercedes renvoie vers la page SF, on ne peut pas passer de paramètre. Il n’est pas possible de savoir quelle Mercedes Connection a été autorisée s’il y en a plusieurs configurées dans SF.

On va donc devoir « marquer » dans la base SF quelle connexion est concernée avant l’appel de la page d’autorisation Mercedes, pour que quand l’utilisateur revient dans SF sur la page d’après-autorisation on retrouve la connexion concernée.

On a ajouté deux champs à l’objet Mercedes Connection :

  • Last_Autorisation_Request_Time__c : la dernière fois qu’un utilisateur a demandé l’autorisation
  • Last_Autorisation_Request_User__c : quel utilisateur a demandé l’autorisation

Avant d’aller vers la page d’autorisation Mercedes, on va marquer la connexion ainsi en mémorisant que la connexion vient d’être demandée par l’utilisateur et que cela vient de se faire.

3.         Page pour demander la connexion

On va créer un composant visuel qui sera placé sur les objets Mercedes Api Connection.

Ce composant va permettre de cliquer sur un bouton pour aller sur le serveur Mercedes pour activer la connexion.

a)              Le composant visuel

C’est un simple composant qui affiche l’Id de la connexion et un bouton pour appeler la page de connexion

<template>

<lightning-card title="Connection Information" icon-name="standard:people">
<div class="slds-m-around_medium">
<p>The connection is </p>
<ul>
<li>SF ID : {recordId}</li>
</ul>
 
</div>
<lightning-button label="Activate Connection" onclick={handleActivateConnection} variant="brand"></lightning-button>
</lightning-card>
 
</template>

b)              Le code javascript du composant

Dans le code javascript du composant, ce qu’il y a de particulier est que :

  • Le code handleActivateConnection appelle d’abord une méthode memorizeAutorisationRequestContext du serveur (Apex) pour stocker le fait qu’on vient de lancer le processus pour cette connexion (voir paragraphe suivant)
memorizeAutorisationRequestContext( {aConnectionId :  this.recordId })
  • Quand cela a marché, dit d’aller vers la page de connexion Mercedes (l’URL est calculée par le code coté serveur) :
this[NavigationMixin.Navigate]({
"type" : "standard__webPage",
attributes: {
"url" : this.autorisationPageURL.data
}
}

Cela donne le code suivant pour le javascript du composant :

import { LightningElement, api, wire } from 'lwc';
import { getRecord /*, getFieldValue */ } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';

import memorizeAutorisationRequestContext from '@salesforce/apex/MercedesAPI.memorizeAutorisationRequestContext';

import getAuthorizationPageURL from '@salesforce/apex/MercedesAPI.getAuthorizationPageURL';

import CONNECTION_SALEFORCE_ID from '@salesforce/schema/Mercedes_API_Connection__c.Id';

import CONNECTION_CLIENT_ID from '@salesforce/schema/Mercedes_API_Connection__c.Mercedes_API_Client_ID__c';

import CONNECTION_CLIENT_SECRET from '@salesforce/schema/Mercedes_API_Connection__c.Mercedes_API_Client_Secret__c';

import CONNECTION_ACCESS_TOKEN from '@salesforce/schema/Mercedes_API_Connection__c.Mercedes_API_Acces_Token__c';


const connectionFields = [
CONNECTION_SALEFORCE_ID,
CONNECTION_CLIENT_ID,
CONNECTION_CLIENT_SECRET,
CONNECTION_ACCESS_TOKEN
];

export default class MercedesConnectionManager extends NavigationMixin(LightningElement)
{

@api recordId; // Connection Id
@wire(getRecord, { recordId: '$recordId', fields: connectionFields })
mercedesConnection;

@wire(getAuthorizationPageURL, {  aConnectionId: '$recordId' })
autorisationPageURL;
get urlInfos() {
return JSON.stringify(this.autorisationPageURL);
}

handleActivateConnection() {
memorizeAutorisationRequestContext( {aConnectionId :  this.recordId })
.then(result => {
// small event message
const evt = new ShowToastEvent({
title: 'Connection Context Memorized',
message: 'The connection context has been successfully memorized for '+result,
variant: 'success',
});
this.dispatchEvent(evt);
// go to page
this[NavigationMixin.Navigate]({
"type" : "standard__webPage",
attributes: {
"url" : this.autorisationPageURL.data
}
},
{
replace: true
}
);
})
.catch(error => {
const evt = new ShowToastEvent({
title: 'Connection Context Not Memorized',
message: 'An error occured '+JSON.stringify(error),
variant: 'error',
});
this.dispatchEvent(evt);
});
}
}

c)              Le code Apex

C’est le code du côté Salesforce qui fait les calculs et les sauvegarde (dans la classe MercedesAPI).

Avant d’aller vers la page d’autorisation Mercedes, on marque la connexion ainsi :

@AuraEnabled(cacheable=false)
public static id memorizeAutorisationRequestContext(Id aConnectionId) {
// recupere la connection
Mercedes_API_Connection__c theConnection = [
SELECT
Id,
Name,
Last_Autorisation_Request_User__c,
Last_Autorisation_Request_Time__c
FROM Mercedes_API_Connection__c
where id = :aConnectionId
];

// memorise qui et quand
theConnection.Last_Autorisation_Request_User__c = UserInfo.getUserId();
theConnection.Last_Autorisation_Request_Time__c = System.now();

// sauve le resultat
update theConnection;

return aConnectionId;
}

Et le code qui calcule la page pour demander l’autorisation d’accès à Mercedes

@AuraEnabled(cacheable=true)
public static String getAuthorizationPageURL(Id aConnectionId) {
Mercedes_API_Connection__c myConnection = [
SELECT
Id,
Mercedes_API_Client_ID__c
FROM Mercedes_API_Connection__c
WHERE id = :aConnectionId
];

return API_URL_Authorization
+ '?response_type=code'
+ '&client_id=' + myConnection.Mercedes_API_Client_ID__c
+ '&redirect_uri='+redirectURI
+ '&scope='+requestedScope;

}

d)              Les informations du composant pour indiquer qu’il est affichable sur les pages ‘Mercedes Api Connection’

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="mercedesConnectionManager">

<apiVersion>45.0</apiVersion>

<isExposed>true</isExposed>

<targets>
<target>lightning__RecordPage</target>
</targets>

<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Mercedes_API_Connection__c</object>
</objects>
</targetConfig>

</targetConfigs>

</LightningComponentBundle>

e)              Le composant ajouté à la page de l’objet API Connection

On ajoute le composant à la page comme on avait fait avant pour le composant qui affichait la couleur d’une voiture.

4.         Page qui récupère les informations de demande d’autorisation

Quand on clique sur le lien, on arrive chez Mercedes où on peut valider qu’on autorise l’accès, puis Mercedes redirige sur la page Mercedes API Authorization (ce qu’on avait fait dans la partie d’avant)

Il faut maintenant faire que cette page utilise le code d’autorisation qu’elle a récupéré

a)              La page

Pour cela on ajoute un bouton sur la page

<apex:page controller="Mercedes_API_Authorization_Ctrl" >
Authorization : {! authorizationCode}
<apex:form >
  <apex:commandButton value="validate connection request" action="{!saveAuthorizationCode}" />
</apex:form>
</apex:page>

Le bouton appelle une action saveAuthorizationCode dans le contrôleur de la page (Mercedes_API_Authorization_Ctrl )

b)              Le code Apex

Du coup, quand on revient dans l’environnement SF de l’utilisateur on peut retrouver la bonne connexion pour y sauver les informations de session (token, etc.) : on prend la dernière connexion modifiée par cet utilisateur

public PageReference saveAuthorizationCode() {

mercedesConnection = [
SELECT
Id,
Name,
Mercedes_API_Client_ID__c,
Mercedes_API_Client_Secret__c,
Mercedes_API_Autorization_Code__c
FROM Mercedes_API_Connection__c
where
Last_Autorisation_Request_User__c= : UserInfo.getUserId()
order by Last_Autorisation_Request_Time__c desc
limit 1
];

….

}
  1. c) On utilise le code de connexion qu’on avait auparavant recopié dans une classe MercedesAPI pour pouvoir le réutiliser.
MercedesAPI api = new MercedesAPI(
theConnection.Mercedes_API_Client_ID__c,
theConnection.Mercedes_API_Client_Secret__c
);
api.initSession(authorizationCode);
  1. d) On stocke l’autorisation et les tokens obtenus
theConnection.Mercedes_API_Autorization_Code__c = authorizationCode;
theConnection.Mercedes_API_Acces_Token__c = api.access_token;
// sauver les autres champs ici
update theConnection;

Et voilà la connexion est établie !

Voici le code avec tous les morceaux mis ensemble.

 
public PageReference saveAuthorizationCode() {

Mercedes_API_Connection__c theConnection = [
SELECT
Id,
Mercedes_API_Client_ID__c,
Mercedes_API_Client_Secret__c,
Mercedes_API_Autorization_Code__c
FROM Mercedes_API_Connection__c
// where id = :monID
limit 1
];

MercedesAPI api = new MercedesAPI(
theConnection.Mercedes_API_Client_ID__c,
theConnection.Mercedes_API_Client_Secret__c
);

api.initSession(authorizationCode);
api.getVehicules();

theConnection.Mercedes_API_Autorization_Code__c = authorizationCode;
theConnection.Mercedes_API_Acces_Token__c = api.access_token;

// sauver les autres champs ici
update theConnection;

vehiculeTexte = api.vehiculesJson;
return null;
}

Et on peut demander à rafraîchir cette partie de page après le clic sur le bouton

<apex:commandButton value="validate connection request" action="{!saveAuthorizationCode}" reRender="vehiculesPanel"/>

Voici ce qu’on voit quand on arrive sur la page ‘redirect url’ après être passé sur le serveur Mercedes :

Puis ce qu’on voit quand on clique sur ‘Validate’

La connexion est maintenant active et le token de session est enregistré.

5.         Rafraichissement automatique du token de connexion

Normalement, le jeton de session n’est valide qu’une heure. Il faudrait faire un code qui appel l’API pour rafraîchir automatiquement le token toutes les heures.

Je ne l’ai pas fait dans le temps de mon Trape.

C’est une amélioration à faire. Pour le moment, il faut recliquer sur ces écrans toutes les heures.

A la découverte de salesforce (2/3) – Développer des composants visuels

Dans Salesforce, une fois que l’on a configuré comme avant, on peut juste utiliser l’outil que Salesforce nous propose pour saisir des objets ou les voir ou les chercher.

Mais pour ce projet, je dois aller plus loin, et j’ai besoin de programmer des écrans spéciaux ou des calculs. C’est cette partie de programmation que j’avais déjà faite dans mes travaux personnels précédents (« Histoire des langages de programmation » et « Développer un jeu en Java »).

Dans cette partie du travail on va découvrir comment programmer dans Salesforce.

1.         Les outils

Pour pouvoir programmer dans Salesforce j’ai dû installer deux outils sur mon ordinateur.

a)              SFDX CLI (Command Line Interface)

Cet outil là nous sert à envoyer les programmes et les configurations réalisés vers Salesforce et de réceptionner ceux déjà réalisés.

Voici le guide pour l’installer :

https://developer.salesforce.com/docs/atlas.en-us.218.0.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm#sfdx_setup_install_cli

b)              Visual Studio

Pour travailler plus facilement j’ai installé un programme qui s’appelle Visual Studio. Dans ce programme on peut programmer facilement. C’est un outil comme Eclipse qu’on avait utilisé pour programmer en Java dans le Travail Personnel Précédent.

Voici le guide qui explique comment l’installer.

https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.install_setup_develop

Comme indiqué dans le guide d’installation, à cet outil on doit ajouter un pack d’extensions qui lui permet de savoir manipuler Salesforce et le CLI. : le Salesforce Extension Pack for Visual Studio Code.

Voilà, nous sommes prêts pour développer en Salesforce !

2.         Un premier test : Un panneau sur la voiture qui affiche sa couleur

Comme premier essai dans ce nouveau programme on va créer un petit panneau qui va afficher la couleur de la voiture.

a)              Créer un projet

Comme dans Eclipse il faut tout d’abord créer un projet dans Visual Studio où on va placer notre code.

Pour créer un projet, dans Visual Studio, on fait Ctrl shift P, on tape « SFDX :Create Project », on donne son nom « Cars » et l’endroit où stocker le projet sur le PC.

b)              Créer le composant

Une fois que le projet est prêt, pour créer le composant que l’on veut développer, on fait un clic droit sur le répertoire lwc du projet Cars, et on sélectionne « create lightning web component ». On lui donne son nom « Car Info ».

 

Visual studio a créé du coup trois fichiers pour le composant :

  • CarInfos.html : la page visible
  • CarInfos.js : le code du programme
  • CarInfos.js-meta.xml : des infos sur ce qu’on peut faire avec le composant

Pour coder ces trois fichiers, j’ai utilisé les exemples décrits dans le manuel du développeur Salesforce.

c)              Développer le composant Car Info

On dit qu’il est affichable dans la page d’une voiture dans CarInfos.js-meta.xml


<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="CarInfo">
<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Car__c</object>
</objects>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>

On code un contenu simple pour CarInfo.html : afficher la variable CarColor.


<template>
<lightning-card title="Car Information" icon-name="standard:people">
<div class="slds-m-around_medium">
<p>the car is {carColor}!</p>
</div>
</lightning-card>
</template>

On écrit le code javascript pour demander à SF la couleur dans CarInfos.js :

  • Au début du code, les lignes import {} cela dit que l’on utilise des possibilités de Salesforce
  • La ligne import CAR_COLOR_FIELD sert à dire qu’on va accéder aux voitures de la base de données SF
  • La ligne @api recordId sert à dire que le composant connaît la voiture qu’il doit afficher (cela va être passé par Salesforce au composant affiché).
  • La ligne @wire… sert à charger les informations de la voiture en mémoire et sa couleur…)
  • La fonction getCarColor est celle appelée par la page HTML pour obtenir la couleur.


import { LightningElement, api, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

import CAR_COLOR_FIELD from '@salesforce/schema/Car__c.Car_Color__c';

const carFields = [CAR_COLOR_FIELD];

export default class CarInfo extends LightningElement {

@api recordId; // Car Id

@wire(getRecord, { recordId: '$recordId', fields: carFields })
car;

get carColor() {
    return getFieldValue(this.car.data, CAR_COLOR_FIELD);
}

}

d)              Envoyer le composant dans Salesforce

Avant d’envoyer le code vers Salesforce, on doit connecter le Visual Studio à Salesforce : Cela se fait dans le terminal du studio en tapant

sfdx force:auth:web:login -d -a mydevorg

Visual Studio ouvre une fenêtre qui demande de se connecter à Salesforce pour me connecter à mon environnement de développement.

 

Mon environnement Salesforce est alors relié à Visual Studio.

Maintenant, je peux envoyer le code du composant vers Salesforce en tapant :

sfdx force:source:deploy -p force-app -u thibault.leblond@wollef.org

e)              Installer le composant dans Salesforce sur la page voiture

La dernière étape est dans Salesforce d’éditer la page affichant la voiture pour ajouter le composant à la page.

On va sur une page qui affiche une voiture, en haut à droite on va dans le menu « Edit Page »

On arrive dans l’éditeur de page, le composant est disponible et peut être placé où l’on veut dans la page

f)               Utiliser le composant sur la page voiture

Une fois que l’on a sauvé la page, le composant s’affiche comme prévu : on a maintenant notre composant visuel en haut à droite !