Archives de catégorie : SharePoint Foundation

Erreurs fréquentes avec le mode feuille de données

On m’a posé plusieurs questions cette semaine en lien avec le mode feuille de données alors j’ai cru bon de vous partager les diverses solutions.

Message d’erreur :

« Impossible de coller les informations car la zone coupé ou copiée et la zone de collage ne sont pas de la même taille. Cliquez sur une seule cellule et réessayez de procéder au collage. »

Voici les étapes pour reproduire le problème :

1. En mode Feuille de données, sélectionnez les lignes à copier

erreurCopierModeFeuilleDeDonnees1

2. Sélectionnez la dernière ligne

erreurCopierModeFeuilleDeDonnees2

3. Effectuez un « Coller »

erreurCopierModeFeuilleDeDonnees

Solution 

La solution se retrouve pourtant dans le deuxième bloc du message d’erreur mais une image vaut parfois mille mots.

Il suffit donc de positionnez le curseur dans la première cellule et non pas la ligne au complet :

erreurCopierModeFeuilleDeDonnees3

 

Message d’erreur :

« Les cellules sélectionnées sont en lecture seule. »

Voici les étapes pour reproduire le problème :

Créer une colonne de type « Plusieurs lignes de texte »

erreurCopierModeFeuilleDeDonnees6

En mode Feuille de données, lorsque vous tentez de saisir une valeur dans un champ de types « Plusieurs lignes de texte »

erreurCopierModeFeuilleDeDonnees5

Vous obtenez le message :

erreurCopierModeFeuilleDeDonnees4

Solution 

La solution consiste à retirer le champ « Plusieurs lignes de textes » de l’affichage ou encore de transformer celui-ci en un champ de type, « Texte brut ».

erreurCopierModeFeuilleDeDonnees7

Par la suite dans le mode feuille de données vous serez en mesure de modifier les valeurs :

erreurCopierModeFeuilleDeDonnees8

 

Advertisements

Alternative à Silverlight pour afficher des vidéos dans SharePoint 2010

Introduction

Depuis un bon moment déjà, Chrome à cesser de supporter les plugins NPAPI. Ceci a pour effet que le composant WebPart multimédia qui utilise Silverlight dans SharePoint 2010 ne fonctionne plus dans Chrome. Puisqu’il fonctionne encore dans Internet Explorer, cela occasionne des comportements différents entre les navigateurs. Dans certaines entreprises, YouTube et Vimeo ne sont pas une option alors dans ce billet je vous propose une solution permettant l’affichage de vidéo autant dans Chrome que dans Internet Explorer.

Utilisation d’un lecteur vidéo qui imite celui de HTML 5

Le lecteur vidéo MediaElementJs permet d’afficher des vidéos dans un seul interface visuel dans tous les navigateurs avec uniquement du JavaScript/CSS.

Il utilise le HTML5 pour les navigateurs récents et Flash/SilverLight afin d’imiter les balises HTML5 pour les anciens navigateurs.

L’intégration du lecteur vidéo dans SharePoint est relativement simple via une WebPart éditeur de contenu. Référez-vous au site de MediaElementJs pour les balises à insérer.

Si jamais les boutons ne s’affiche pas dans le lecteur vidéo, il vous suffit d’ajouter un MIME dans IIS sur vos serveurs SharePoint :

MIME_SVG

  1. Ouvrir IIS Manager et sélectionner votre Application Web.
  2. Dans Features View, double cliquer sur MIME Types.
  3. Dans l’onglet Actions, cliquer sur Add.
  4. Dans la boîte de dialogue « Add MIME Type » inscrire « .svg » dans le champ « File name extension ».
  5. Inscrire « image/svg+xml » dans le champ « MIME type » .
  6. Cliquer sur  OK.Source : http://technet.microsoft.com/en-us/library/cc725608(v=ws.10).aspx

Résultat

Chrome (HTML 5 player):

mediaElementsChrome

Internet Explorer 8.0 (Flash Player) :

mediaElementIE8

Conclusion

Bien évidemment, il s’agit d’une solution de contournement pour SharePoint 2010 car déjà dans SharePoint 2013, le lecteur vidéo permet d’afficher des vidéos en HTML 5 puis dans SilverLight pour les anciens navigateurs.

Références

Mediaelementjs.com

Comparatif des lecteurs vidéo HTML 5

 

Comparatif des différentes possibilités pour afficher des tableaux de bord dans SharePoint

Introduction

Il existe plusieurs façons d’afficher des tableaux de bord dans SharePoint. Cependant, les possibilités peuvent varier selon la version (2010/2013/2016) et le type de déploiement sur site (On Premise) ou dans SharePoint Online. Il est donc facile de passer plusieurs heures avant de se rendre compte que la solution envisagée n’est pas compatible avec la version en place. Dans ce billet, je vais mettre en évidence les différentes possibilités pour afficher des tableaux de bords (dashboard) puis fournir un comparatif par fonctionnalité et par version.

Power BI

PowerBI

Source : PowerBI

Il s’agit de l’offre BI de Microsoft en tant que service hébergé dans le cloud. Malgré que la solution repose dans le cloud, il est possible de s’alimenter de données sur site (On Premise) et il est possible d’incorporer un tableau de bord dans presque toute les plateformes Web. Microsoft investit beaucoup d’argent dans cette plateforme et pour cette raison, il y a des mises à jours régulièrement. Une communauté très active permet entre autre d’avoir accès à une galerie de visuels pour vos tableaux de bord.

Outils tiers

sales-dashboard_Collabion

Source : Collabion

Plusieurs outils tiers sont disponibles pour ajouter la possibilité d’afficher des tableaux de bord dans SharePoint. Les fonctionnalités sont différente selon le produit sélectionné. Par exemple : le nombre de visualisation disponible ou le nombre de connexion à des sources de données. Pour n’en nommer que quelque uns : Collabion, Bamboo et Kwizcom.

Solution personnalisé avec du code client

GoogleChart.PNG

Source : Google Charts

Le nombre de librairie client disponible pour afficher des tableaux de bord est grandissant. Une solution personnalisée peut ainsi facilement utiliser une de ces librairies afin d’afficher des tableaux de bord très intéressant via un Add-In ou une WebPart Éditeur de contenu. Pour n’en nommer que quelque unes : Google Charts, jqPlot Charts et Chartjs.

Solution personnalisé avec du code serveur

Telerik

 

Source : Telerik

Il existe aussi quelque librairies serveur pour afficher des tableaux de bord. On peut alors réaliser une solution personnalisée en utilisant une de ces librairies via une Visual WebPart et généralement un service Web. Pour n’en nommer que quelque unes : Telerik, ComponentOne et Crystal report.

 

SQL Reporting Services (SSRS)

ssrs

Source : SSRS

SSRS est un logiciel de génération de rapport serveur de Microsoft qui fait partit de la suite SQL Serveur. Un générateur de rapport peut permettre à quelqu’un qui n’est pas technique de réaliser des tableaux de bord. Autrement, des interfaces dans Visual Studio permettent de réaliser des rapports plus complexe. Il existe aussi des WebParts pour afficher les rapports directement dans une page SharePoint.

PerformancePoint

PerformancePoint

Source : cdhtalkstech.com

PerformancePoint est un outil de Microsoft disponible dans la version Entreprise de SharePoint 2010-2016 mais qui n’a pas vraiment évolué depuis la première version. Il est possible de créer des tableaux de bords à partir de quelque sources de données dont des cubes provenant de SSAS. Des WebParts spécifique à PerformancePoint sont aussi disponible pour un affichage directement dans SharePoint.

Excel BI / Power View

PowerView

Source : blogs.msdn.microsoft.com

Power View constitue une expérience d’exploration, de visualisation et de présentation interactives des données qui encourage la génération intuitive de rapports ad hoc. Power View est une fonctionnalité de Microsoft Excel 2013 et Microsoft SharePoint Server 2010 et 2013 disponible avec le complément SQL Server 2012 Service Pack 1 Reporting Services de Microsoft SharePoint Server Enterprise Edition.

PowerPivot

PowerPivot

Source : Youtube.com

PowerPivot est un complément pour Microsoft Excel 2010 qui vous permet d’importer des millions de lignes de données à partir de plusieurs sources de données dans un classeur Excel unique, de créer des relations entre les données hétérogènes, de créer des mesures et des colonnes calculées à l’aide de formules, de créer des tableaux croisés dynamiques et des graphiques croisés dynamiques, puis d’analyser ces données afin de pouvoir prendre des décisions opportunes sans nécessiter d’assistance informatique.

Visio Services dans SharePoint 2013

Visio.png

Source : Sharepointpromag.com

Visio Services permet aux utilisateurs de partager et d’afficher des diagrammes Visio dans SharePoint. Il permet également l’actualisation et la mise à jour des diagrammes Visio connectés à des données à l’aide de différentes sources de données. Visio Services s’exécute en tant qu’application de SharePoint Server 2013.

SharePoint 2010 Composant WebPart Graphique (Chart Web Part)

Pie ChartBar Chart

Source : Support.office.com

Le composant WebPart Graphique est un composant WebPart qui peut être créé et ajouté à un site SharePoint pour permettre aux utilisateurs d’afficher un tableau de bord. Cette WebPart n’a pas évolué depuis la version 2010 mais il est encore possible de l’utiliser dans SharePoint 2010-2016.

Comparatif des solutions par fonctionnalité

Visualisation personnalisée
Incorporer dans d’autres outils
Impression et exportation
Connexion à plusieurs source de données
Aucun codage requis
Power BI ~20 types Mark Mark ~ 60 sources Mark
Outils tiers ~1-50 types Mark Mark ~ 10 sources Mark
Solution personnalisé avec du code client warning-icon warning-icon
Solution personnalisé avec du code serveur warning-icon warning-icon
SQL Reporting Services (SSRS) 12 types Mark Mark ~10 sources warning-icon
PerformancePoint 8 types Mark  ~5 sources
Excel BI / Power View ~11 types Mark Mark 5 sources
PowerPivot ~10 types Mark Mark 4 sources Mark
Visio Services dans SharePoint 2013 Mark warning-icon 5 sources Mark
SharePoint 2010 Composant WebPart Graphique (Chart Web Part)  13 types ~3 sources Mark

 Mark Supporté

warning-icon Possible avec contournement

∞   Illimité

Comparatif des solutions par version

SP2010 SP2013 SP2016 SharePoint Online
Power BI Mark Mark Mark Mark
Outils tiers Mark Mark Mark Mark
Solution personnalisé avec du code client Mark Mark Mark Mark
Solution personnalisé avec du code serveur Mark Mark Mark warning-icon
SQL Reporting Services (SSRS) Mark Mark Mark
PerformancePoint Mark Mark Mark
Excel BI / Power View Mark Mark
PowerPivot Mark Mark Mark
Visio Services dans SharePoint 2013 Mark Mark Mark Mark
SharePoint 2010 Composant WebPart Graphique (Chart Web Part) Mark warning-icon warning-icon

Légende

 Mark Supporté

warning-icon Possible avec contournement

∞    Illimité

Conclusion

Les possibilités sont nombreuses pour afficher des tableaux de bord dans SharePoint. Certaines solutions n’ont pas évoluées depuis quelques versions ce qui en dit long concernant leur pérennité. Dans ce sens, je crois que PowerBI se démarque du lot au niveau des fonctionnalités et en second je considère que les outils tiers comme Collabion sont une bonne alternative au développement personnalisé.

Les solutions évoluent très rapidement alors si vous voyez des erreurs n’hésitez pas à m’en faire part et j’apporterai les ajustements.

Quelles solutions de tableau de bord utilisez-vous dans votre entreprise ?

Créer des filtres dynamiques sur vos List View WebPart avec du JS + KnockoutJS

Introduction

Jusqu’à tout récemment, j’utilisait une WebPart de filtre avec une connexion afin de filtrer l’année de publication des nouvelles :

Actualites

Cependant, ça ne fonctionne pas lorsqu’on utilise la pagination ET le filtre.  Le problème c’est que la pagination ajoute les paramètres de filtre directement dans le Querystring Ex : FilterField1=PublishedDateYear&FilterValue1=2016. Par la suite, même si on change de valeur via la WebPart de filtre, la valeur qui sera appliqué sera toujours celle du Querystring.

Je n’ai malheureusement pas trouvé de solution élégante à cette problématique alors j’ai plutôt opté pour une solution en JavaScript qui m’offre plus de flexibilité.

Une solution 100 % JS

Je me suis basé sur un article que j’ai trouvé sur le blog de Phil Harding et je l’ai adapté à mon besoin. Le résultat est très intéressant et nous allons voir en détail comment mettre le tout en place dans ce billet. Voici tout d’abord un bref aperçu :

ActualitesFiltreDynamique

Le code peut être exécuté autant dans SP2010 que SP2013 mais il y a quelque subtilité au niveau du code.

Intégration du code

La solution utilise une WebPart Éditeur de contenu pointant vers un fichier « txt » qui contient le balisage HTML. Ce fichier « txt » contient des références vers un fichier JS, CSS et au Framework Knockout JS v3.1.0.

La structure des fichiers est la suivante :

  • /Style Library/txt/script_actualites_filtre_html.txt (Gist)
  • /Style Library/css/app_filtre.css (Gist)
  • /Style Library/scripts/app_filtre.js (Gist)
  • /Style Library/scripts/knockout-3.1.0.js (Source)

La première étape consiste à copier vos fichiers dans votre dossier Style Library et à ajuster les références.

Ensuite, dans une page contenant une List View WebPart ajouter une WebPart Éditeur de contenu avec un lien vers le fichier : /Style Library/txt/script_actualites_filtre_html.txt.

Puis, adapter le fichier app_filtre.js (Voir les TODO dans le code) afin que vos filtres correspondent à vos colonnes et à votre liste.

app_filtre.js


(function(module,$j) {
"use strict";

window.pd = window.pd || {};

pd.MeetingsViewModel = function() {
   /* observable state */
   this.FilterTextIm = ko.observable('');
   this.FilterText = ko.computed(this.FilterTextIm)
                        .extend({ throttle: 400 });
   this.LibraryTitle = ko.observable('');
   this.LibrarySubTitle = ko.observable('');
   this.FilterYears = new ko.observableArray([]);
   this.FilterMonths = new ko.observableArray(['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre']);
   this.SelectedYear = ko.observable('');
   this.SelectedMonth = ko.observable('');
   this.Working = ko.observable(true);

   /* populate years filter as Current Year..-=4 */
   for(var cy = parseInt(new Date().getFullYear()), y = cy; y > (cy-3); y--) { this.FilterYears.push(y.toString()); }

   /* model actions */
   this.filterByYear = function(year) {
      this.FilterTextIm('');   // zap the filter text
      year = (year === this.SelectedYear()) ? '' : year;
      this.SelectedYear(year);
   }.bind(this);
   this.filterByMonth = function(month) {
      this.FilterTextIm('');   // zap the filter text
      month = (month === this.SelectedMonth()) ? '' : month;
      this.SelectedMonth(month);
   }.bind(this);

   /* model behaviour */
   this.isSelectedYear = function (year) {
      var y = this.SelectedYear();
      return (y == year);
   }.bind(this);
   this.isSelectedMonth = function (month) {
      var m = this.SelectedMonth();
      return (m == month);
   }.bind(this);
}


pd.FilterLibraryApp = function() {
   var
      viewModel = new pd.MeetingsViewModel(),
      debug = true,
      wpCtx = null,
      wpEvent = null,
      
      filterControlId = null,
      listViewTableId = null,
      _module = {
         start: start
      };
   return _module;

   function locateListView() {
      var fn = function() {
         InitAllClvps();

         // find the CTX for the LVWP
         for(var k in g_ctxDict) {
           if (debug && window.console) console.log(g_ctxDict[k]);
           
           if (g_ctxDict[k].ListTitle === module.LibraryTitle) {
             wpCtx = window['ctx'+g_ctxDict[k].ctxId];
             break;
           }
         }
         if (debug && window.console) {
            console.log(wpCtx.clvp);
            console.log(wpCtx.clvp.ctx);
            console.log(wpCtx.clvp.ctx.view);
         }
         /* this isn't used in the 2010 version, not figured out if/how to use it yet 
         var clvp = (wpCtx && wpCtx.clvp) ? wpCtx.clvp : null;
         wpEvent = { clvp: clvp, event: { currentCtx: { clvp: clvp } } };
         */
         
         // find the LVWP and table containing the rows
         var 
            $wpnode = $j('#'+wpCtx.clvp.wpq).first(),
            $wpTableNode = $wpnode.find("table[id^='onetidDoclibViewTbl']");
         listViewTableId = $wpTableNode.attr('id');

		 //Il faut avoir préalablement coché la case "Afficher le bouton de raffraichisement" sur la LVWP

         // find the postback control id; e.g. ctl00$m$g_109629d4_d78b_4c9e_8ec0_90078b6e444e$ctl02
         var
            $wpinput = $wpnode.find('> :first-child > input:first-child'),
            ctrlid = $wpinput.attr('id');
         ctrlid = ctrlid && ctrlid.length
                     ?  ctrlid.replace(/^(ctl\d\d)_/gi,'$1$')
                               .replace(/_g_/g,'$g_')
                               .replace(/_(ctl\d\d)$/gi,'$$$1')
                     : '';
         if (debug && window.console) { console.log(">>locateListView: controlid="+ctrlid); }
         filterControlId = ctrlid;
         viewModel.LibraryTitle(wpCtx.ListTitle);
         viewModel.LibrarySubTitle('All');
         viewModel.Working(false);
      };
      EnsureScript("inplview", typeof InitAllClvps, fn);
   }

   function onFilterChange(filterType) {
      if (!filterControlId) {
         alert('Unable to filter: the list view webpart could not be located or the list view contains a Person/Group column!');
         return;
      }

      var
         filterColumn = null,
         filterValue = '';

      if (filterType.match(/year/gi)) {
         filterValue = this.SelectedYear();
         filterColumn = 'PublishedDateYear'; //TODO ajuster votre filtre
      } else if (filterType.match(/month/gi)) {
         filterValue = this.SelectedMonth();
         filterColumn = 'PublishedDateMonth'; //TODO ajuster votre filtre
      }

      if (!filterValue) filterValue = '##dvt_all##';
      var filterCall = "__doPostBack('"+filterControlId+"','NotUTF8;__filter={"+filterColumn+"="+filterValue+"}')"

      if (debug && window.console) {
         console.log(">>Filter by " + filterType + " on ["+filterColumn+"] = ["+filterValue+"]");
         console.log("  >> " + filterCall);
      }
      eval(filterCall);
   }

   function start() {
      ko.applyBindings(viewModel, $j('#cdtm').get(0));
      viewModel.SelectedYear.subscribe(onFilterChange.bind(viewModel, 'year'));
      viewModel.SelectedMonth.subscribe(onFilterChange.bind(viewModel, 'month'));

      locateListView();
   }
}();

$j(pd.FilterLibraryApp.start);

})({ Name: 'Module', LibraryTitle: 'Billets' },jQuery); //TODO Ajuster le titre de votre liste


Dernier détail

Afin de pouvoir lier les filtres à la vue, pour ma part j’ai été contraint de cocher la case suivante :

ActualitesFiltreDynamiqueLVWP

Sans cela, le controlid était toujours vide. Si vous avez une erreur vérifier tout d’abord votre console (F12) :

ActualitesFiltreDynamiqueLVWPConsole

Conclusion

Seulement avec du JS on a réussi à ajouter des filtres dynamiques sur une List View WebPart et cela fonctionne correctement avec la pagination. Donc, beaucoup de flexibilité au niveau du déploiement et de la personnalisation visuelle.

Référence

Dynamically Filtering SharePoint List Views using Javascript

Envoyer des courriels périodiques pour SharePoint OnPrem avec du PowerShell

Introduction

SharePoint dispose d’un mécanisme d’alerte assez puissant. Celui-ci permet d’envoyer à l’abonné une alerte par courriel basé sur une action qui se produit sur l’élément (il est créé, modifié, etc…). Il comporte cependant des limitations :

  • On ne peut pas recevoir une alerte périodique (ex : tous les trimestres, tous les premiers Lundi du mois, etc…);
  • La modification du gabarit de courriel est complexe;
  • Il n’est pas possible de modifier l’adresse de réponse et le sujet pour une alerte en particulier;
  • Vous devez être que propriétaire du site afin d’envoyer des alertes à d’autres personnes. Sans cela, la seule personne à qui vous pouvez envoyer des alertes à est vous-même.

Alors que faire si on veut contourner ces limitations?

Il y a quelques solutions possibles :

  1. Créer un timer job SharePoint (Exemple)
  2. Créer un flux de travail (Exemple)
  3. Utiliser un logiciel tiers (Exemple)
  4. Créer un script PowerShell s’exécutant dans une tâche planifié (Source)

Je vais mettre l’emphase sur le point 4 dans ce billet car à mon avis c’est la meilleure alternative lorsque les alertes « out-of-the-box » ne répondent pas à votre besoin.

Comparaison des différentes solutions

Alertes SharePoint out-of the-box Timer Job personnalisé

 

Flux de travail personnalisé Outil tiers

Script PowerShell

Flexibilité Mark Mark
Permet de modifier le contenu dynamique envoyé facilement Mark Mark Mark Mark
Permet de modifier le visuel du gabarit sans avoir besoin de programmation Mark Mark Mark
Envoyer des courriels à des utilisateurs externes Mark Mark
Nécessite peu d’efforts de configuration Mark Mark
Permet d’envoyer un courriel basé sur un intervalle de temps Mark Mark Mark
Gratuit Mark Mark Mark Mark

 

Utiliser un script PowerShell

Le script pour SharePoint 2013 sur site (OnPrem) est disponible ici :

telecharger-bouton

Assurez-vous de modifier la section « Constantes » et d’y inscrire les valeurs correspondants à votre environnement.

Capture

Celui-ci va créer une liste EmailTemplate :

EmailTemplate

Cette liste permet à un utilisateur de piloter les différentes valeurs sans avoir besoin d’effectuer de la programmation lorsque vient le temps de changer le contenu, le sujet, etc… Bien évidemment, si vous ajoutez d’autres modèles, vous devrez ajuster votre code afin de les utiliser correctement.

Le script va aussi créer une liste Project :

ProjectListView

Celle-ci est uniquement présente à des fins de démonstration. C’est à partir de cette liste que nous allons envoyer du contenu dynamique par courriel. Vous pouvez donc la supprimer et vous alimenter de votre propre liste si vous le souhaitez.

Voici un exemple de courriel envoyé par le script :

EmailResult

Exécution du script PowerShell dans une tâche planifiée

Démarrer -> Exécuter -> Taskschd.msc

Créer une nouvelle tâche :

ScheduledTaskPowerShell_create

Spécifier un compte ayant les droits d’administrateur de la ferme SharePoint.

Spécifier un déclencheur :

ScheduledTaskPowerShell_declencheur

Ajouter une nouvelle action :

ScheduledTaskPowerShell_action

Programme/Script : Powershell.exe

Ajouter des arguments : -ExecutionPolicy Bypass C:\Sources\SharePointerie.OnPrem.SendTimeBasedEmail.ps1

En prenant soin d’adapter le chemin vers votre script.

Cliquer sur OK pour enregistrer la tâche.

Outils de développeur pour faciliter le travail avec les courriels

Pour ma part, j’utilise l’outil SMTP4DEV afin de travailler en mode local. Il suffit de démarrer l’application et celle-ci se chargera d’intercepter les envois de courriel sur le port défini.

smtp4Dev

Source : https://smtp4dev.codeplex.com/

Conclusion

L’utilisation d’un script PowerShell pour envoyer des courriels périodiques permet un maximum de flexibilité autant au niveau du déploiement qu’au niveau du pilotage. Il n’y a pas de période d’indisponibilité lors du déploiement comparativement au déploiement d’un Timer Job. Je crois donc que c’est la meilleure alternative lorsque les alertes out-of-the-box ne répondent pas à votre besoin.

Techniques pour récupérer les éléments HTML d’une WebPart en JavaScript

Introduction

Dans ce billet je vous propose quelque techniques de JavaScript pour pouvoir récupérer les éléments HTML d’une WebPart spécifique. Chez un de mes clients je me suis vite rendu compte qu’il n’était pas évident d’avoir une « poigné » fixe pour appliquer une personnalisation sur une seule WebPart. Le Client Side Rendering (CSR) est à la mode c’est temps-ci mais il comporte une certaine complexité en comparaison aux quelques lignes de JavaScript qui suivront. Pour ce qui est du CSS, il n’est pas évident de l’appliquer seulement à une WebPart.

Examinons le code généré d’une WebPart

En appuyant sur F12 dans une page contenant des WebParts, vous pourrez examiner le code HTML généré par celle-ci.

Voici un exemple :

WebPartByTitle_HTMLElement

Vous remarquerez qu’il y a un ID unique sur chacune des WebParts de la page.

L’élément DIV avec le ID « MSOZoneCell_WebPartWPQ6 » correspond à l’ensemble de la WebPart.

L’élément DIV avec le ID « WebPartWPQ6_ChromeTitle » correspond à l’entête de la WebPart.

L’élément SPAN avec le ID « WebPartTitleWPQ6 » correspond au titre de la WebPart.

Voyons maintenant quelque techniques pour les récupérer.

Technique 1 – Récupérer les éléments HTML d’une WebPart par son titre

Cette technique consiste à utiliser le titre de la WebPart comme poigné pour récupérer les éléments HTML d’une WebPart précise.

Voici le code pour y arriver :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
     //Parcours tous les éléments SPAN ayant un ID qui commencent par WebPartTitleWPQ
     $("span[id^=WebPartTitleWPQ]").each(function()
     {
          //Si le titre de la WebPart commence par "Site Collection Documents"
          if($(this).attr('title').indexOf("Site Collection Documents") == 0){
          //Applique une personnalisation sur l'ensemble de la WebPart (Couleur rouge)
               $(this).parent().parent().css('background-color', 'red');
          }
    });
});
</script>

Résultat

Le background-color rouge est appliqué uniquement sur la WebPart avec le titre « Site Collection Documents » :

WebPartByTitle_After

Points à faire attention avec cette technique

  1. Assurez-vous d’avoir un titre unique pour vos WebParts
  2. Assurez-vous d’utiliser un type de chrome incluant le « Titre »

Au besoin, vous pouvez modifier le titre de votre WebPart ou le type de chrome :

WebPartByTitle_MenuWP

Technique 2 – Récupérer les éléments HTML d’une WebPart par son ID

Cette technique consiste à utiliser l’ID comme poigné pour récupérer les éléments HTML d’une WebPart précise.

Voici un exemple de code pour modifier une WebPart par sont ID :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
 //Applique une personnalisation à l'ensemble de la WebPart (Couleur bleu) par son ID
 $("#MSOZoneCell_WebPartWPQ6").css('background-color', 'blue');
});
</script>

Résultat

Le background-color bleu est appliqué uniquement sur la WebPart avec le ID MSOZoneCell_WebPartWPQ6 :

WebPartByID_After

Points à faire attention avec cette technique

  1. Assurez-vous d’ajuster votre code si une WebPart est déplacé,  ajouté ou supprimé

Que se passe-t’il si on déplace une WebPart ou qu’on en ajoute une nouvelle?

Le ID de la WebPart va tout simplement changer.

Avant la suppression d’une WebPart (2 WebParts) :

WebPartByTitle_HTMLElement_AvantDelete

WebPart 1 : WebPartWPQ4_ChromeTitle

 

Après la suppression d’une WebPart (1 WebPart) :

WebPartByTitle_HTMLElement_ApresDelete

WebPart 1 : WebPartWPQ2_ChromeTitle 

Voici un autre exemple qui utilise cette technique.

Conclusion

Les deux techniques présentés dans cet article peuvent vous permettre facilement d’appliquer des personnalisations sur un élément HTML d’une WebPart. La première technique utilisant le titre de la WebPart n’est pas sans faille si deux WebParts se retrouvent avec le même nom. Pour ce qui en est d’utiliser le ID de l’élément HTML de la WebPart, il faut faire attention si on déplace, supprime ou ajoute une WebPart dans la page car les ID sont susceptible de changer et ainsi de rendre votre code non fonctionnel. Ces techniques peuvent vous permettre d’appliquer des modifications rapidement lorsque ce n’est pas possible de le faire avec du CSS ou que c’est trop complexe avec du Client Side Rendering.

Message d’erreur lors de la publication d’un flux de travail SharePoint 2010 contenant plus de 5 processus d’approbation

Introduction

Dernièrement, nous avons réalisé un flux de travail assez complexe en terme de logique pour un de nos client. Il contient 7 formulaires Infopath et il utilise plusieurs processus d’approbation. Le diagramme Visio entre difficilement dans dans une page 8½ x 11 !

Malheureusement, nous avons rencontré un problème majeur lors de la publication de ce flux de travail.

Voici le contexte de l’environnement :

  • Flux de travail de liste
  • Flux de travail SharePoint 2010
  • Créé à partir de SharePoint Designer 2013
  • Ferme SharePoint 2013

Lors de nos tentatives de publication on obtient toujours ce message d’erreur :

« Erreur lors de la compilation du flux de travail »

« Erreur inattendue sur le serveur associant le flux de travail »

wf

Investigations et problématique

On a alors investigué plusieurs pistes sans succès :

  • Augmenter les « timeout » dans les fichiers web.config et dans les pool applicatifs
  • Investiguer les fichiers de Logs ULS / Obsérvateur d’événements
  • Essayer sur d’autres postes
  • Vider la cache de SharePoint Designer 2013
  • Vider la cache du serveur
  • Redémarrer le serveur

Puis on est tombé sur cette article à propos du même message d’erreur lorsqu’on a plusieurs processus d’approbation. On a donc réalisé que notre flux de travail complexe contenait trop d’étape d’approbation (8) ! On en a alors enlevé (3) et suite à cela on a été en mesure de le publier sans problème.

Solutions possibles

  • Rendre le flux de travail moins complexe en retirant des processus d’approbation
  • Séparer le flux de travail en plusieurs flux de travail
  • Remplacer quelque processus d’approbation par des processus de tâche personnalisée qui sont moins complexe

Reproduire le problème

Pour reproduire le problème, suivre les étapes suivantes :

1. Créer un flux de travail de liste sur une liste de votre choix :

wf_step1

2. Donner un nom à votre flux et sélectionner « Flux de travail SharePoint 2010 » :

wf_step2

3. Ajouter 5 processus d’approbation avec le menu « Action -> Démarrer le processus d’approbation » :

wf_processus

4. Choisir au moins un utilisateur dans le champ « Utilisateur » :

wf_5processus

5. Publier le flux de travail

wf_step5

6. La publication se déroulera alors sans problème.

7. Ajouter un autre processus d’approbation :

wf_6processus

On obtient alors le message d’erreur.

Conclusion

Ce problème ne semble pas être documenté auprès de Microsoft et à mon avis, il s’agit d’une limitation au niveau de la complexité des flux de travail. Je vous suggère donc de faire plusieurs flux de travail simple au lieu d’un seul gros flux de travail complexe qui est susceptible de se déployer difficilement.