Présentation et configuration du modèle de transformation de pageUnderstanding and configuring the page transformation model

Le cœur de la solution de transformation de page est le modèle qui alimente la transformation : le modèle indique au moteur les propriétés du composant WebPart qui sont importantes, vous permet de manipuler ces propriétés et de choisir dynamiquement un mappage pour votre composant WebPart.The heart of the page transformation solution is the model that feeds the transformation: the model tells the engine which web part properties are important, allows you to manipulate these properties and dynamically choose a mapping for your web part. Le modèle de transformation de page est exprimé en XML et est fourni avec un schéma qui permet de valider l’exactitude du modèle.The page transformation model is expressed in XML and comes with a schema that's used to validate the correctness of the model.

Important

L’infrastructure de modernisation SharePoint PnP est en constante évolution. Pour être informé des dernières modifications, consultez les notes de publication.The SharePoint PnP Modernization framework is continuously evolving, checkout the release notes to stay up to date on the latest changes. Si vous rencontrez des problèmes, signalez-les dans la liste de problèmes GitHub sp-dev-modernization.If you encounter problems please file an issue in the sp-dev-modernization GitHub issue list.

Architecture de haut niveau de transformation de pagePage transformation high level architecture

L’image suivante représente les 4 étapes de la transformation de vos pages :Below picture explains the page transformation in 4 steps:

  1. Tout d’abord, fournissez au moteur de transformation un modèle de transformation de page.At the start you need to tell the transformation engine how you want to transform pages and that's done by providing a page transformation model. Ce modèle est un fichier XML qui décrit comment chaque composant WebPart classique doit être mappé avec un composant WebPart moderne équivalent.This model is an XML file which describes how each classic web part needs to be mapped to a modern equivalent. Pour chaque composant WebPart classique, le modèle contient une liste de propriétés pertinentes et d’informations de mappage.Per classic web part the model contains a list of relevant properties and mapping information. Pour en savoir plus, consultez l’article relatif à la présentation et configuration du modèle de transformation de page.See the Understanding and configuring the page transformation model article to learn more. Pour avoir une comparaison des composants WebPart classiques et des composants WebPart modernes, nous vous recommandons de consulter l’article relatif aux expériences de composant WebPart classique et moderne.If you want to understand how classic web parts compare to modern web parts it's recommended to checkout the Classic and modern web part experiences article.
  2. L’étape suivante consiste à analyser la page à transformer : le moteur de transformation répartit la page dans une collection de composants WebPart (le texte wiki est réparti dans un ou plusieurs composants WebPart de texte wiki) et tente de détecter la mise en page utilisée.Next step is analyzing the page you want to transform: the transformation engine will break down the page in a collection of web parts (wiki text is broken down in one or more wiki text web parts) and it will try to detect the used layout.
  3. Les informations récupérées de l’analyse à l’étape 2 ne suffisent généralement pas à mapper le composant WebPart avec un composant WebPart moderne équivalent. C’est pourquoi, à l’étape 3, nous allons améliorer les informations en appelant des fonctions : ces fonctions prennent les propriétés récupérées à l’étape 2 et génèrent de nouvelles propriétés basées sur les propriétés entrées à l’étape 2.The information retrieved from the analysis in step 2 is often not sufficient to map the web part to a modern equivalent and therefor in step 3 we'll enhance the information by calling functions: these functions take properties retrieved in step 2 and generate new properties based upon the inputted properties from step 2. Après l’étape 3, nous avons toutes les informations nécessaires pour mapper le composant WebPart... à l’exception du fait que nous devons appeler le sélecteur défini pour comprendre le mappage dont nous aurons besoin au cas où un composant WebPart classique peut être mappé à plusieurs configurations modernes.After step 3 we have all the needed information to map the web part...except we optionally need to call the defined selector to understand which mapping we'll need in case one classic web part can be mapped to multiple modern configurations.
  4. La dernière étape consiste à créer et à configurer la page moderne suivie de l’ajout des composants WebPart modernes mappés à celle-ci.The final step is creating and configuring the modern page followed by adding the mapped modern web parts to it.

Transformation de page

Structure du modèle de transformation de pagePage transformation model structure

Quand vous ouvrez le modèle de transformation de page, les éléments de niveau supérieur suivants apparaissent :When you open the page transformation model the following top level elements are present:

  • BaseWebPart : cet élément contient la configuration qui s’applique à tous les composants WebPart. Par exemple, il indique que la propriété « Titre » est extraite pour tous les composants WebPart.BaseWebPart: this element contains the configuration that applies to all web parts e.g. it describes that the property "Title" will be fetched for all web parts. Il s’agit également du lieu qui définit le mappage de composants WebPart par défaut : si aucun mappage n’est défini pour le composant WebPart, le moteur revient au mappage pour représenter le composant WebPart sur la page cible.It's also the place that defines the default web part mapping: if a web part has no mapping defined the engine will fall back to this mapping to represent the web part on the target page.

  • Addons: en tant qu’utilisateur de la transformation de page, vous avez peut-être besoin d’appliquer une logique personnalisée pour répondre à vos besoins, par exemple, vous devez transformer une propriété donnée de manière à ce qu’elle fonctionne avec votre composant WebPart SPFX personnalisé.AddOns: as user of page transformation you might have needed to apply custom logic to realize your needs e.g. you need to transform a given property in a way that it can work with your custom SPFX web part. L’infrastructure prend en charge cet aspect en vous permettant d’ajouter vos assemblies avec les fonctions et les sélecteurs. En les définissant simplement dans la section AddOn et en référençant ensuite vos fonctions et vos sélecteurs personnalisés en y ajoutant en préfixe un nom donné, vous demandez à la transformation de page d’utiliser votre code personnalisé.The framework supports this by allowing you to add your assemblies with functions and selectors...simply defining them in the AddOn section and then referencing your custom functions and selectors later on by prefixing them with the given name will make the page transformation use your custom code.

  • WebParts : cet élément contient des informations pour chaque composant WebPart à transformer.WebParts: this element contains information for each web part that you want to transform. Pour chaque composant WebPart, vous trouverez une définition des propriétés à utiliser, les fonctions à exécuter sur ces propriétés, les mappages possibles qui définissent la cible de la transformation combinés à un sélecteur qui vous permet de sélectionner dynamiquement le mappage nécessaire.For each web part you'll find a definition of the properties to use, the functions to execute on those properties, the possible mappings that define the target of the transformation combined with a selector that you dynamically select the needed mapping.

De plus amples informations vous seront fournies dans les prochains chapitres.Upcoming chapters will provide more details.

Définition du composant WebPart dans le modèle de transformation de pageWebPart definition in the page transformation model

Nous allons analyser comment un composant WebPart est configuré dans le modèle de transformation de page. Pour cela, nous vous recommandons d’utiliser un exemple simplifié de la définition de XsltListViewWebPart :Let's analyze how a web part is configured in the page transformation model, which is best done based upon a simplified sample of the XsltListViewWebPart definition:

      <!-- XsltListView web part -->
      <WebPart Type="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
        <Properties>
          <Property Name="XmlDefinitionLink" Type="string" />
          <Property Name="ListUrl" Type="string" />
          <Property Name="ListId" Type="guid" Functions="{ListWebRelativeUrl} = ListAddWebRelativeUrl({ListId}); {ListServerRelativeUrl} = ListAddServerRelativeUrl({ListId})"/>
          <Property Name="Direction" Type="string"/>
          <Property Name="GhostedXslLink" Type="string" />
          <Property Name="DisableViewSelectorMenu" Type="bool"/>
          <Property Name="XmlDefinition" Type="string" Functions="{ListViewId} = ListDetectUsedView({ListId},{XmlDefinition})"/>
          <Property Name="SelectParameters" Type="string"/>
        </Properties>
        <!-- This selector outputs: Library, List  -->
        <Mappings Selector="ListSelectorListLibrary({ListId})">
          <Mapping Name="List" Default="true">
            <ClientSideText Text="You can map a source web part ({Title}) to a combination of modern web parts :-)" Order="10" />
            <ClientSideWebPart Type="List" Order="20" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;false,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
          </Mapping>
          <Mapping Name="Library" Default="false">
            <ClientSideWebPart Type="List" Order="10" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;true,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
          </Mapping>
        </Mappings>
      </WebPart>

Élément PropertiesProperties element

Pour chaque composant WebPart, le modèle définit les propriétés qui peuvent être utiles pour configurer le ou les composants WebPart modernes cibles.For each web part the model defines the properties that might be useful to configure the target modern web part(s). Si vous ratez certaines propriétés, vous pouvez simplement les étendre dans le modèle.If you miss certain properties you can simply extend them in the model. Sur certaines propriétés, vous verrez un attribut Functions : cet attribut contient une ou plusieurs fonctions (fonctions distinctes via une ;) qui sont exécutées lorsque le composant WebPart source est mappé à un composant WebPart moderne cible.On some of the properties you'll see a Functions attribute: this attribute contains one or more functions (separate functions via a ;) that are executed when the source web part is mapped to a target modern web part. Voici l’anatomie d’une fonction :The anatomy of a function is the following:

{Output} = FunctionName({Input1}, {Input2})

Une fonction peut posséder une ou plusieurs valeurs d’entrée, notamment :A function can have one or more input values which can be:

  • Les propriétés définies sur ce composant WebPart (par exemple, {ListId})Properties defined on this web part (e.g. {ListId})
  • Les propriétés définies dans le composant WebPart de base (par exemple, {Title})Properties defined on the base web part (e.g. {Title})
  • Les propriétés correspondant à la sortie des exécutions de la fonction précédente (par exemple, {ListWebRelativeUrl})Properties that were the output of previous function executions (e.g. {ListWebRelativeUrl})
  • Les propriétés d’étendue de site par défaut : {Host}, {Web}, {Site}, {WebId}, {SiteId}Default site scoped properties: {Host}, {Web}, {Site}, {WebId}, {SiteId}

Lorsqu’une fonction est exécutée, le résultat est le suivant :When a function runs its output will either be:

  • Une valeur de chaîne unique : cette valeur ({Output} dans le modèle présenté) est ajoutée à la liste des propriétés du composant WebPart appelées « Output » et à la valeur renvoyée à partir de l’exécution de FunctionName.A single string value: this value ({Output} in the presented model) will be added to the list of web part properties with name "Output" and value the value that was returned from running FunctionName.
  • Une liste de paires clé/valeur (Dictionary<string, string>) : chaque paire clé/valeur renvoyée est ajoutée à la liste des propriétés du composant WebPart.A list of key/value pairs (Dictionary<string,string>): in this case each returned key/value pair is added to the list of web part properties

Si la fonction ne définit pas le paramètre de sortie, la valeur de la propriété du composant WebPart qui définit la fonction est remplacée par le résultat de la fonction.If the function does not define the output parameter then value of the web part property that defines the function will be overwritten with the function result.

Voici un exemple pour éclaircir ce point :Let's clarify with a sample:

<Property Name="ListId" Type="guid" Functions="FormatGuid({ListId})"/>

Supposons que la propriété du composant WebPart contienne à l’origine un GUID mis en forme de la manière suivante : {AAFAD7D0-D57A-4BB1-8706-969A608C686B}.Let's assume that the web part property originally contains a guid formatted like {AAFAD7D0-D57A-4BB1-8706-969A608C686B}. Une fois que la fonction FormatGuid est exécutée, la valeur est définie sur la sortie de la fonction FormatGuid (par exemple, un GUID sans les crochets AAFAD7D0-D57A-4BB1-8706-969A608C686B).After FormatGuid has been executed the value will be set to the output of FormatGuid (e.g. a guid without brackets AAFAD7D0-D57A-4BB1-8706-969A608C686B).

Si une fonction renvoie plusieurs valeurs, chaque paire clé/valeur renvoyée qui existe déjà comme propriété du composant WebPart remplace la valeur de cette propriété.If a function returns multiple values then each returned key/value pair that already exists as web part property overwrites that properties value.

Notes

Toutes les fonctions prêtes à l’emploi sont décrites dans l’article sur les sélecteurs et fonctions de transformation de pageAll the out-of-the box functions are described in Page Transformation Functions and Selectors

Élément MappingsMappings element

Cet élément définit une ou plusieurs configurations cibles possibles pour le composant WebPart source donné.This element defines one or more possible target configurations for the given source web part. Comme vous pouvez définir plusieurs cibles, un mécanisme doit être mis en place pour déterminer le mappage à utiliser :Since you can define multiple targets there needs to be a mechanism to determine which mapping to use:

  • Si l’élément Mapping contient un attribut « Selector » rempli, la sortie de l’exécution du sélecteur sert à rechercher le mappage approprié par son nom (par exemple, la fonction du sélecteur ListSelectorListLibrary renvoie « Library », ce qui génère le mappage « Library » en cours d’utilisation).If the mapping element contains a filled Selector attribute then the output of the selector execution is used to find the correct mapping by name (e.g. selector function ListSelectorListLibrary return string "Library" which results in the mapping with name "Library" being used). Les sélecteurs sont identiques aux fonctions renvoyant une seule valeur. Ainsi, vous pouvez spécifier un attribut de composant WebPart comme entrée dans la fonction de votre sélecteur.Selectors are identical to functions that return a single value, so you can specify any web part attribute as input to your selector function
  • S’il n’y a qu’un seul mappage, celui-ci est pris en compte s’il n’y avait aucun résultat du sélecteur.If there's only one mapping then that's taken if there was no selector result
  • S’il n’y a aucun résultat du sélecteur et qu’il existe plusieurs mappages définis, le mappage marqué comme valeur par défaut est pris en compte.If there's no selector result and there are multiple mappings defined then the mapping marked as Default is taken

Notes

Tous les sélecteurs prêts à l’emploi sont décrits dans l’article Sélecteurs et fonctions de transformation de pageAll the out-of-the box selectors are described in Page Transformation Functions and Selectors

Vous trouverez ci-dessous une description de l’élément Mapping.Next up is explain the Mapping element itself.

Élément MappingMapping element

À l’intérieur d’un élément Mapping, vous pouvez avoir un ou plusieurs éléments ClientSideText ou ClientSideWebPart comme indiqué dans l’extrait de code ci-dessous.Inside a Mapping element you can have one or more ClientSideText or ClientSideWebPart elements as shown in below snippet. Notez que vous pouvez exécuter des fonctions sur un mappage, ce qui est pratique pour le cas où vous souhaiteriez effectuer un traitement uniquement si un mappage particulier a été sélectionné.Note that you can run functions on a Mapping, which is handy in case you want to do processing only if a particular mapping was selected.

<Mapping Name="List" Default="true" Functions="{SampleVariable} = SampleFunction({ListId})>
  <ClientSideText Text="You can map a source web part ({Title}) to a combination of modern web parts :-)" Order="10" />
  <ClientSideWebPart Type="List" Order="20" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;false,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
</Mapping>

Dans l’exemple ci-dessus, le composant WebPart XSLTListView source est mappé à unClientSideTextcomposant de texte moderne () etClientSideWebPartà un composant WebPart moderne () :In above sample the source XSLTListView web part is mapped to a modern text part (ClientSideText) and a modern web part (ClientSideWebPart):

  • Utilisez l’attribut Order pour déterminer le composant qui apparaît en premier.Use the Order attribute to determine which one comes first
  • Pour un composant ClientSideWebPart, spécifiez le Type du composant WebPart. Si vous choisissez le type Custom, spécifiez également la propriété ControlId pour identifier le composant WebPart personnalisé nécessaire.For a ClientSideWebPart you need to specify the Type of the web part, if you choose Custom as type you'll also need to specify the ControlId property to identify the needed custom web part
  • Les propriétés Text, JsonControlData et ControlId peuvent contenir des jetons sous la forme {Token}, qui sont remplacés par des valeurs réelles pendant l’exécution.The Text, JsonControlData and ControlId properties can contain tokens in the form of {Token} which are replaced by actual values at runtime. Chaque jeton défini doit être activé comme propriété de composant WebPart ou comme résultat de la fonction, comme expliqué précédemment.Each token defined needs be able as web part property or function result as explained earlier on

Définition des éléments AddOns dans le modèle de transformation de pageAddOns definition in the page transformation model

Les modules complémentaires (AddOns) vous permettent d’insérer votre logique personnalisée dans le modèle de mappage en suivant ces 2 étapes :Add-ons allow you to insert your custom logic into the mapping model by following these 2 steps:

  • Créer un assembly personnalisé qui héberge vos fonctions/sélecteurs personnalisésCreate a custom assembly hosting your custom functions/selectors
  • Déclarer cet assembly personnalisé dans les éléments AddOnsDeclare this custom assembly in the AddOns elements

Créer un assembly fonctions/sélecteurs personnaliséCreate your custom functions/selectors assembly

Pour créer vos propres fonctions, référencez l’assembly SharePoint.Modernization.Framework dans votre projet, puis créez une classe qui hérite de la classe SharePointPnP.Modernization.Framework.Functions.FunctionsBase :To create your own functions you'll need to reference the SharePoint.Modernization.Framework assembly in your project and then create a class inheriting the SharePointPnP.Modernization.Framework.Functions.FunctionsBase class:

using Microsoft.SharePoint.Client;
using SharePointPnP.Modernization.Framework.Functions;
using System;

namespace Contoso.Modernization
{
    public class MyCustomFunctions: FunctionsBase
    {
        public MyCustomFunctions(ClientContext clientContext) : base(clientContext)
        {
        }

        public string MyListAddServerRelativeUrl(Guid listId)
        {
            if (listId == Guid.Empty)
            {
                return "";
            }
            else
            {
                var list = this.clientContext.Web.GetListById(listId);
                list.EnsureProperties(p => p.RootFolder.ServerRelativeUrl);
                return list.RootFolder.ServerRelativeUrl;
            }
        }

    }
}

Déclarer un assembly personnaliséDeclare your custom assembly

Avant d’utiliser les fonctions personnalisées, elles doivent être déclarées dans le modèle en ajoutant une référence par bibliothèque/classe dans l’élément AddOns :Before custom functions can be used they need to be declared in the model by adding one reference per library/class into the AddOns element:

<AddOn Name="Custom" Type="Contoso.Modernization.MyCustomFunctions" Assembly="Contoso.Modernization.dll" />

ou (notez le chemin d’accès complet)or (note the fully qualified path)

<AddOn Name="Custom" Type="Contoso.Modernization.MyCustomFunctions" Assembly="c:\transform\Contoso.Modernization.dll" />

Notez que chaque déclaration porte un nom (« Custom » dans l’exemple ci-dessus).Note that each declaration has a name, "Custom" in above sample.

Utiliser les fonctions/sélecteurs personnalisésUse your custom functions/selectors

Une fois l’assembly défini, vous pouvez utiliser vos fonctions et sélecteurs en les référençant par leur nom (par exemple, par le préfixe « Custom » dans l’exemple ci-dessous) :Now that the assembly has been defined you can use your functions and selectors be referencing them by the name like you see the "Custom" prefix in below sample:

<Property Name="ListId" Type="guid" Functions="{ListServerRelativeUrl} = Custom.MyListAddServerRelativeUrl({ListId})"/>