Inherits Cloud

Loving Microsoft Cloud, specially Office 365

SharePoint / Office Dev Patterns & Practices – Liberada la Release de Enero 2017

Como supongo sabréis, soy gran fan del programa SharePoint PnP, así que quería haceros eco de la versión de Enero 2017. Tenéis toda la información detallada en el blog oficial:

 

https://dev.office.com/blogs/pnp-january-2017-release

 

Algunas de las novedades que a mi me parecen mas destacadas:

 

  • Diferentes fixes dentro del framwork de Provisioning
  • Nuevo ejemplo del SP Framework de como llamar a una custom WebAPI securizada con Azure AD desde un webpart del SPFx
  • Posibilidad de exportar la navegacion estructural para sitios de no-publishing
  • PnP JS library usa ahora webpack para el bundle a pnp.min.js
  • Nuevos comandos PowerShell para tratar con la RecycleBin
  • Nuevo comando PowerShell para añadir Image Renditions: Add-PnPPublishiningImageRendition

 

Y entre todas las novedades, este nuevo ejemplo me ha parecido muy interesante react-generic-app ya que muestra como usar el “modern web stack” sin utilizar el nuevo Framework, muy interesante ahora mismo si tienes que empezar un proyecto de SharePoint On Premises.

Nada mas, os animo a descargar la ultima version y empezar a utilizarlo.

 

Saludos!

 

@luismanez

Provisionando Image Renditions con PnP Core y PnP Schema

Una duda bastante recurrente alrededor del framework PnP, es si podemos desplegar/provisionar Image Renditions desde el PnP. La respuesta es si (no hay opción de desplegar una Rendition en concreto, pero podemos usar un “workaround” para desplegar todas las Renditions que necesitemos).

Internamente, cuando se define una Image Rendition en SharePoint, este, simplemente crea un nuevo nodo en un fichero XML, que podéis encontrar en la Master Page Gallery. El nombre del fichero es: PublishingImageRenditions.xml y su contenido es algo como:

 

image

 

Básicamente tenemos un nodo ImageRendition por cada Rendition que queremos definir, con Ancho y Alto de la Rendition.

 

Nota: Cuidado con el nodo NextId, ya que si editamos el fichero a mano, tendremos que darle el valor adecuado, que no es otro que el siguiente ID a asignar en caso de que se agregue posteriormente otra Rendition desde la interfaz de SharePoint.

 

Teniendo en cuenta que las renditions se gestionan desde este fichero, y que el PnP tiene la opción de provisionar ficheros a bibliotecas de SharePoint, el siguiente paso es hacer uso del nodo File dentro del PnP Schema, para desplegar este fichero XML en la Master Page Gallery, para ello, podemos usar el siguiente snippet XML:

 

image

 

El atributo Src define la ubicacion local del fichero, mientras que Folder define la ubicación en SharePoint (en este caso hacemos uso del token ~masterpagecatalog, que el PnP resolvera cuando se aplique la template). Ademas, debemos de especificar el Tipo de Contenido del fichero, que para el caso del fichero de Renditions, es el ID: 0x01010012BCF119622FF14793A8A38D5831F25C.

 

Con todo esto en nuestra PnP template, podremos provisionar nuestras Images Renditions.

 

Espero que os sirva!

 

@luismanez

Que hace MS Teams en mi tenant de Office 365

A principios de mes Microsoft liberó Teams, en sus propias palabras “the chat-based workspace in Office 365” (https://blogs.office.com/2016/11/02/introducing-microsoft-teams-the-chat-based-workspace-in-office-365/).

En este post no hablaremos de Teams, ni puedo daros mucha luz sobre que herramienta utilizar en cada caso, podéis leer este post y veréis que todos andamos algo confundidos “

Dear Microsoft: I’m Confused. Can You Help Me Collaborate Well?”. En este post simplemente os quiero comentar como afecta el uso de Teams a nuestra Tenant de Office 365 y SharePoint.

 

Cada Team es un Group de Office 365

Probablemente ya lo sabéis, pero cuando se crea un Team en MS Teams, un nuevo grupo de Office 365 es creado. De hecho, cuando creas un Team, tienes la opción de decirle que utilice un grupo existente de Office 365.

 

image

 

En principio, parece que solo tienes esa opción cuando el grupo es “Private”, y eres el administrador del grupo.

Podéis ver que los teams creados en Teams, son en realidad grupos de Office 365

 

image image

Cada Team es una Site Collection en SharePoint

Ademas de un grupo de Office 365, cada Team es una site collection de SharePoint, ya que la Tab “Files”, usa SharePoint para almacenar los archivos. Por ejemplo, hay una site collection para el team “Sales group”

 

image

 

Curiosamente, estas Site Collections creadas desde Teams, no son visibles desde el listado de Site Collections del portal de Admin de SharePoint Online, ni tampoco se pueden listar usando CSOM. La verdad es que no se porque no se pueden listar desde CSOM, pero debe ser que MS ha incluido algun filtro en la parte servidor, para no devolverlas en codigo. Sin embargo, si especificais la URL, podeis conectar a la site collection usando CSOM. Yo he trazado con Fidler la respuesta SP al listado de site collections desde CSOM, y la respuesta a cargar una site collection creada con Teams, y la unica diferencia que veo que podria server como filtro desde el servidor, es la propiedad “Status” o “Web template”. Comparando ambos JSON (solo por frikear, ya se que no sirve de nada Smile):

 

image

 

Cada channel de un Team, es un folder en la Documents library

Volviendo a la site collection que se crea con un Team, podemos ver que con cada “Channel” de un Team, se crea un folder en la biblioteca Documents de la site collection:

 

image

 

image

 

Que hay “Searchable” de Teams en SharePoint?

Entonces, quizá os estáis preguntando como yo: Y esta información es “Searchable” en SharePoint? pues hasta donde he visto, NO. Es decir, cuando se crea un Team desde MS Teams, el grupo de Office 365 asociado, se crea como “Private”, y al parecer, no puede ser indexado por el Search, por lo que no aparece nada en los resultados de búsqueda. Sin embargo, un grupo de Office 365 creado como Public, si que aparece en los resultados de la búsqueda, el problema es que, como os decía antes, no se puede crear un Team asociado a un grupo Publico. La siguiente imagen es el resultado de una query a la api search de SP, filtrando por Web Template: Group, y en los resultados solo aparecen los grupos Publicos.

 

image

 

Me parece una limitación importante que el contenido de un Team no sea “discover-able” desde el search de SP (al fin y al cabo, si un usuario pertenece a un Team, deberia poder ver los documentos de ese Team tb como resultados de búsqueda de SharePoint). Igual esto cambie mas adelante, o haya algún oscuro workaround (si lo encuentras compártelo!)

 

Hasta el proximo post!

Saludos.

@Luismanez

[Collab365] – Video “on demand” de mi sesion: Agilizando nuestros desarrollos SharePoint con Gulp y PnP

Os dejo link directo al video de mi sesión de ayer en el Collab 365. Necesitareis registraros para poder acceder, pero vale la pena por la excelente calidad de las sesiones impartidas durante los 2 días del evento.

 

https://collab365.conferencehosts.com/confs/Global2016/c365globalmanez/ConfPages/SessionRoom.aspx

 

Saludos!

 

@Luismanez

[SharePoint Online] Error creando una vista nueva en la Publishing Image library

Si te encuentras con un error al intentar crear una vista nueva en la biblioteca de Images (PublishingImages), que se ha creado por defecto al crear el sitio basado en la plantilla de ENTWIKI (Enterprise Wiki), tranquilo, no has hecho nada malo, es un bug de la template. Es totalmente reproducible en cualquier tenant de SharePoint Online u On Premises. Basta con crear un nuevo site collection o site, basado en la plantilla OOB EntWiki. Una vez creado el sitio, vas a la Publishing Images library, intentas crear una nueva Vista, eliges tipo “Estandar”, y boom! Correlation ID Screen of Death!

issue-new-view

Causa

Por algún extraño motivo, está esperando ciertos campos en la lista que no existen. Esos campos son agregados por el Video Content Type, pero solo cuando la Feature “Video and Rich media” esta activada en el sitio, cosa que no ocurre con la template de Enterprise Wiki.

video-feature

Solución

Para solucionarlo, debes activar dicha Feature a nivel de la Site Collection, pero, además, deberás eliminar el Tipo de Contenido “Video” de la lista, y volverlo a agregar a la misma, de esta forma, todos los campos de “Video” se añadirán a la lista, y ya podrás crear la vista sin problemas.

PnP al rescate!

Si utilizas el framework de Provisioning del PnP, puedes configurar la template para que active la feature, y además, re-aplique el tipo de contenido sobre la lista. El XML seria:

<pnp:ProvisioningTemplate ID="MyTemplate ">

 <pnp:Features>
 <pnp:SiteFeatures>
 <pnp:Feature ID="6e1e5426-2ebd-4871-8027-c5ca86371ead" Description="Video and Rich Media" />
 </pnp:SiteFeatures>
 </pnp:Features>

 <pnp:Lists>
 <pnp:ListInstance Title="Images" Description="This system library was created by the Publishing feature to store images that are used on pages in this site." DocumentTemplate="" TemplateType="851" Url="PublishingImages" EnableVersioning="true" MinorVersionLimit="0" MaxVersionLimit="0" DraftVersionVisibility="0" TemplateFeatureID="4bcccd62-dcaf-46dc-a7d4-e38277ef33f4" ContentTypesEnabled="true" EnableAttachments="false">
 <pnp:ContentTypeBindings>
 <pnp:ContentTypeBinding ContentTypeID="0x0101009148F5A04DDD49CBA7127AADA5FB792B00AADE34325A8B49CDA8BB4DB53328F214" Default="true" />
 <pnp:ContentTypeBinding ContentTypeID="0x0101009148F5A04DDD49CBA7127AADA5FB792B006973ACD696DC4858A76371B2FB2F439A" />
 <pnp:ContentTypeBinding ContentTypeID="0x0101009148F5A04DDD49CBA7127AADA5FB792B00291D173ECE694D56B19D111489C4369D" />
 <pnp:ContentTypeBinding ContentTypeID="0x0120" />
 <pnp:ContentTypeBinding ContentTypeID="0x0120D520A808" />
 </pnp:ContentTypeBindings>
 </pnp:ListInstance> 
 </pnp:Lists>

</pnp:ProvisioningTemplate>

@LuisManez

SharePoint Saturday Barcelona–Materiales de mi sesion “Integracion continua con SharePoint y Visual Studio Team Services”

El pasado Sábado se celebro el SharePoint Saturday Barcelona, organizado por el SUG.cat. El evento fue todo un éxito, y tuve la suerte de participar como Speaker, en una sesión en la que hablamos de Integración Continua en SharePoint con Visual Studio Team Services y el framework del PnP. Además, contamos con ClearPeople como patrocinador.

Tal y como os adelante que haría, he subido a mi sitio de GitHub el proyecto que utilice en la demo, así como las slides de la sesión.

https://github.com/luismanez/sp-saturday-barcelona-2016

De nuevo agradecer a patrocinadores y organizadores por el evento, y recordaros que si tenéis cualquier duda de la sesión, dejadme un mensaje en el sitio de GitHub, por twitter o como queráis Smile

Saludos!

Luis.

Materiales de mi sesión en el pasado SharePoint Saturday Madrid

El pasado 7 de Mayo tuvo lugar en Madrid el SharePoint Saturday. Un extraordinario evento organizado por las distintas comunidades de SharePoint de nuestro país, y que fue todo un éxito, como demostraron las mas de 170 personas que acudieron.

Tuve la suerte de participar como speaker, hablando del framework del PnP para SharePoint, y que os recomiendo encarecidamente.

Os dejo en mi GitHub los materiales de la sesion, tanto el PPT como las demos que hice durante la sesion.

https://github.com/luismanez/sp-saturday-madrid-2016

Para acabar, agredecer de nuevo a los patrocinadores, al equipo organizador… ah! y a mi empresa ClearPeople, por ayudarme a participar.

@luismanez

[Office 365] Managing Search Settings using CSOM

This article will show you how you can manage the different search settings using CSOM. It will configure the search settings in the same way that you can do from the “Search settings” option in the Site settings:

clip_image002

Note that, obviously, the Search Settings that will apply, are the ones defined at Web level. The Site collection level only applies if in the Web level you are selecting: “Use the same results page settings as my parent.”, and actually, what it does is to copy the values to the Web site level.

This is how the Search settings page looks:

clip_image004

The “Configure Search Navigation” option is only available from Web Search settings, and that means you cannot inherit search navigation nodes (as far as I’ve seen). In order to add new Navigation links, the best option is to use the Pnp Core project, and use a handy extension for the Web object, so you can do something like:

   1: web.AddNavigationNode(

   2:     "News Relative", 

   3:     new Uri("/sites/search/Pages/NewsResults.aspx", UriKind.Relative), 

   4:     string.Empty, OfficeDevPnP.Core.Enums.NavigationType.SearchNav, 

   5:     true);

Note that if the page is not in the same Site collection, you have to set the “isExternal” param to true, or you will get an exception when saving changes.

For the other settings, there are no specific CSOM code to configure them. However, SharePoint saves that information in some PropertyBags, so we just need to Update that PropertyBags values with the right information. Here are the PropertyBags that SharePoint uses:

At Site collection search settings level:

image

Remember that these settings doesn’t apply to the RootWeb. They are only used to copy these values when a subsite is created and it inherits the settings from their parent.

At Web search settings level:

image

Considering this, all you have to do to configure Search Settings from CSOM, is to set the property bag value, and again, we can use another Web extension from Pnp Core project:

   1: web.SetPropertyBagValue(

   2:     "SRCH_SB_SET_WEB", 

   3:     @"

   4:         {

   5:             ""Inherit"" : false,

   6:             ""ResultsPageAddress"" : ""sites/docssearch/pages/results.aspx"",

   7:             ""ShowNavigation"" : true

   8:         }

   9:     "

  10:     );

Finally, keep in mind that all these settings apply mainly to the Default search text box control, as you can override some of them from the Search box web part:

clip_image010

[Office 365] Updating user profile from CSOM updates only some properties

Scenario

Since this update (http://blogs.msdn.com/b/vesku/archive/2014/11/07/sharepoint-user-profile-properties-now-writable-with-csom.aspx) on SharePoint client libraries, we can update User Profile properties using CSOM (prior to that, you could use the “old” user profile web service). However, under some circumstances, you can see that some of the properties have been updated, and some others have not.

You are using some code like this to create the PeopleManager

   1: this.peopleManager = new PeopleManager(this.SharepointClientContext);

Then, you have multiple calls to SetSingleValueProfileProperty to update different properties

   1: this.peopleManager.SetSingleValueProfileProperty(

   2:                                 accountName, 

   3:                                 userProfilePropertyName, 

   4:                                 propertyValue);

And finally, you commit the changes to SharePoint:

   1: this.SharepointClientContext.ExecuteQuery();

Cause

It seems that when you are trying to update different properties and you do a final ExecuteQuery, the SharePoint client library actually splits the update query into different requests to the client.svc/ProcessQuery service. I don’t know the exact number of properties where the Client library split into 2 or more requests, but in my case, I was trying to update 18 user profile properties, and considering the first request had 11 properties, seems quite clear that it will split the query if you are updating more than 11 properties in a single ExecuteQuery

I realised about that using the magic from Fiddler. Image below shows the 2 requests, after only one ExecuteQuery call:

clip_image002

Each request sent some XML in the body request like:

clip_image004

So, in my case, the first request was failing because one user profile property was not created in the SharePoint tenant, and I was able to see the error in the response body:

clip_image006

However, as the second request worked fine (all the properties in the body xml existed and the new value was right), the Client library is not raising an exception, so, the code worked fine, but the result was that some properties (the ones included in the first request) were not updated, and some others (second request) were updated.

In my opinion, this behaviour is kind of bug on the Client component, as it should raise an Exception if any partial request fails (or at least, warn it somehow)

Luis Manez

@luismanez

Using the OOB Taxonomy picker control just from JavaScript code in SharePoint Online

In this blog post I’m gonna show you how to use the OOB Taxonomy picker control without any server side control or code, just using JavaScript.

As you probably know, the Taxonomy picker control is the TaxonomyWebTaggingControl class, that looks like:

image image

However, all the core functionality of this control is actually done by JavaScript so, in some cases, can be useful how to reuse all of this functionality without any server side stuff, for example, imagine you can add a Taxonomy picker control using a Script editor web part, letting the user pick a Term and then execute some custom JS code.

If someone is curious, I got all this knowledge with some reflection from the TaxonomyWebTaggingControl class, and some hours reading a lot of JS code that SharePoint generates when you work with Taxonomy fields (no magic Smile)

First thing you need to know is that almos all of the Taxonomy picker control functionality is inside the Script “scriptforwebtaggingui.js”, and if you are working with Taxonomy, likely you’ll also need the file “sp.taxonomy.js”, so, ensure you have a reference to this files an option to this could be using the ScriptLink, if you can edit the MasterPage:

   1: <SharePoint:ScriptLink ID="ScriptLink2" name="scriptforwebtaggingui.js" OnDemand="true" runat="server" Localizable="false" />

   2: <SharePoint:ScriptLink ID="ScriptLink1" name="sp.taxonomy.js" OnDemand="true" runat="server" Localizable="false" />    

or, you can use the SP.SOD framework. Here is the JS code generated by the first ScriptLink above:

   1: RegisterSod("scriptforwebtaggingui.js", "https:u002fu002fcdn.sharepointonline.comu002f10477u002f_layoutsu002f15u002f16.0.2930.1217u002fscriptforwebtaggingui.js");

   2: RegisterSodDep("scriptforwebtaggingui.js", "sp.js");

   3: RegisterSodDep("scriptforwebtaggingui.js", "sp.ui.rte.js");

   4: RegisterSodDep("scriptforwebtaggingui.js", "scriptresources.resx");

From HTML code, the Taxonomy picker control needs 2 html tags:

  • One tag is a hidden tag, and will save the selected terms in the format: Label|Term_GUID;OtherLabel|TermGUID…
  • The other tag is a DIV container, where JS code will inject the control, the show picker image, autocomplete options, and so on
   1: <input name="countryTaxControl" type="hidden" id="countryTaxControl">

   2: <div id="countryTaxControlContent" class="ms-taxonomy ms-taxonomy-height ms-taxonomy-width"></div>  

Now, you need to Initialize the control from more JavaScript code. As you likely will need the Taxonomy JS code and a SharePoint context, this is a good way to ensure all the JS files needed are loaded first:

   1: SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {

   2:     SP.SOD.executeFunc('sp.taxonomy.js', 'SP.Taxonomy.TaxonomySession', init);

   3: });

Then, in the Init function, let’s initialize the Taxonomy picker control:

   1: var tagUI = document.getElementById(taxControlContentId);

   2: if (tagUI) {

   3:     tagUI['InputFieldId'] = taxControlInputId;

   4:     tagUI['SspId'] = sspId;

   5:     tagUI['GroupId'] = '00000000-0000-0000-0000-000000000000';

   6:     tagUI['TermSetId'] = termSetId;

   7:     tagUI['AnchorId'] = '00000000-0000-0000-0000-000000000000';

   8:     tagUI['IsMulti'] = isMulti;

   9:     tagUI['AllowFillIn'] = false;

  10:     tagUI['WidthCSS'] = 'ms-taxonomy-width';

  11:     tagUI['JavascriptOnValidation'] = "";

  12:     tagUI['Lcid'] = 1033;

  13:     tagUI['IsSpanTermSets'] = false;

  14:     tagUI['IsSpanTermStores'] = false;

  15:     tagUI['IsIgnoreFormatting'] = false;

  16:     tagUI['IsIncludeDeprecated'] = false;

  17:     tagUI['IsIncludeUnavailable'] = false;

  18:     tagUI['IsIncludeTermSetName'] = false;

  19:     tagUI['IsAddTerms'] = false;

  20:     tagUI['IsIncludePathData'] = false;

  21:     tagUI['IsUseCommaAsDelimiter'] = true;

  22:     tagUI['Disable'] = false;

  23:     tagUI['ExcludeKeyword'] = false;

  24:     tagUI['WebServiceUrl'] = _spPageContextInfo.webServerRelativeUrl + 'u002f_vti_binu002fTaxonomyInternalService.json';

  25:     tagUI['FieldName'] = fieldName;

  26:     tagUI['FieldId'] = '00000000-0000-0000-0000-000000000000';

  27:     tagUI['DisplayPickerButton'] = showPickerButton;

  28:     var _emmTaggingLoadCall;

  29:     if (_emmTaggingLoadCall == null) {

  30:         _emmTaggingLoadCall = true;

  31:         SP.SOD.executeFunc('ScriptForWebTaggingUI.js', 'Microsoft.SharePoint.Taxonomy.ScriptForWebTaggingUI.taggingLoad',

  32:             function () {

  33:                 Microsoft.SharePoint.Taxonomy.ScriptForWebTaggingUI.resetEventsRegistered();

  34:             });

  35:     }

  36:     SP.SOD.executeFunc('ScriptForWebTaggingUI.js', 'Microsoft.SharePoint.Taxonomy.ScriptForWebTaggingUI.onLoad',

  37:         function () {

  38:             Microsoft.SharePoint.Taxonomy.ScriptForWebTaggingUI.onLoad(taxControlContentId);

  39:         });

  40: }

Most of the params are self-explained, and also are the same params in the TaxonomyWebTaggingControl class. Interesting params are:

  • taxControlContentId: this is the ID from the DIV container in the HTML I showed you above.
  • InputFieldId: ID of the Hidden control.
  • SspId: This is the TermStore ID. I’ll show you later how to get that ID from more JS code.
  • termSetId: Term set ID that you want to bind the control. You can get it using sp.taxonomy.js, for example, get the ID from the TermSet name.

Here is the code to get the Term Store ID (SspId):

   1: var context = new SP.ClientContext.get_current();

   2: var session = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);

   3: var termStore = session.getDefaultSiteCollectionTermStore();        

   4:  

   5: context.load(session);

   6: context.load(termStore);

   7:  

   8: context.executeQueryAsync(

   9:     function () {

  10:         sspId = termStore.get_id();

  11:         sspId = sspId.toString();

  12:         //configure controls ...

  13:     },

  14:     function () {

  15:         console.log("Unable to access Managed Metadata Service.")

  16:     }

  17: );

Finally, let’s say you wanna set a value before loading the control, for example, you get the Field value or a User profile Taxonomy property, and you want to set the control with that value. In this case, you just have to set the Hidden control value, like:

   1: $("#regionTaxControl").val("SharePoint|123413456-aaaa-aa11-aa22-123456789012;Javascript|123413456-aaaa-aa11-aa22-123456789012");

You have to do that before configuring the control, before calling the:

   1: Microsoft.SharePoint.Taxonomy.ScriptForWebTaggingUI.onLoad(taxControlContentId);

and that’s all ! you will get all the Taxonomy picker functionality and styling (obviously, you have to manage what you wanna do with the selected values, the loading and saving functionality is not done by the control)

Last note

If you’re using SharePoint apps and want to use the Taxonomy picker, you can use the code from AMS Office code, where Richard diZerega has made a great job creating a JS control with almost same functionality that the OOB Taxonomy picker control.

Also, that code can be used inside SharePoint, as is using just jQuery and SP JSOM. I did it and worked fine. However, that control has some lacks comparing with the OOB, like for example, you can’t use the keyboard to select the Terms, only the mouse (users are use to type, use the arrows, and enter tab to select a Term). This can’t be done with the code sample (unless I did some wront, didn’t worked that way to me). Of course, this is some sample code, and you have the entire source to adapt it to your needs.

Hope it helps!

Luis Manez
@luismanez

« Siguientes entradas

© 2017 Inherits Cloud

Tema por Anders NorenArriba ↑