miércoles, 26 de noviembre de 2014

Cómo solventar la limitación del “wait for X to equal” en SPD 2013

Anteriormente publiqué un post sobre algunas de las incoherencias que había detectado en los flujos de SharePoint Designer en 2013. Una de ellas es la de que en SPD 2013 la acción de esperar hasta que cambie el valor de un campo de la lista había pasado de ser muy flexible en 2010 (to equal, to not equal, to be not empty, to begin with…) a extremadamente inflexible en 2013 (única y exclusivamente “to equal”).

En SPD 2010         En SPD 2013
[image%255B8%255D.png]       [image%255B11%255D.png]

Así pues, si tenemos un flujo de trabajo que está esperando una validación, y el resultado de la validación puede ser tanto “Aprobada” como “Rechazada”, ¿Cómo lo hacemos?

En su momento apunté la posibilidad de invocar un flujo en 2010 que lo solucionara (cosa que me provoca picores en todo el cuerpo), pero hoy os planteo otra posible solución que (mientras no contemple un número muy elevado de posibles respuestas) es más “polite” y debería darnos menos dolores de cabeza.

La solución no es otra que la de diseñar pasos en ejecución paralela. Es decir, allí donde queramos introducir la instrucción de esperar a que el campo tome uno de los posibles valores (en este ejemplo “rejected” o “approved”), tendremos que:

1.- Introducir un bloque de ejecución en paralelo.image
2.- Crear tantos “steps” dentro del bloque de ejecución en paralelo como posibles respuestas podamos obtener. En este caso 2, una para rechazo y otra para validación.
image
image
A partir de aquí rellenar las acciones necesarias para cada respuesta, teniendo en cuenta que únicamente será posible ejecutar una de ellas (o hay validación o hay rechazo). Si hubieran acciones comunes en todos los casos, estas se pueden poner fuera y al después de la ejecución paralela, ya que se ejecutarían una vez uno de los pasos dejara de estar en modo de espera y avanzara en el flujo.
Como resultado obtendríamos un flujo más o menos con la siguiente pinta:
image
¡Pues ya lo tenemos! Una vez más sorteando las “piedras” en el camino de la implementación de SharePoint. Confiemos en que SharePoint 2015 aporte muchas más mejoras y muchas menos limitaciones y bugs… ¡¡Soñar es gratis!! Guiño

domingo, 23 de noviembre de 2014

SP 2013: Cómo crear una alerta con parpadeo de imagen (Javascript)

Los que conocen este blog sabrán que siempre he tirado más por la vertiente de IT Pro (administrator/power user) y resolver las trabas de SharePoint mediante trucos OOB o SharePoint Designer y otras herramientas zero code. Pero últimamente he estado trabajando en un proyecto de SharePoint sobre el que básicamente hemos tenido que utilizar Javascript y jQuery para implantar todos los requerimientos del cliente, y como “me ha entrado el gusanillo”, hoy vamos a explicar un ejemplo práctico de jQuery que he utilizado recientemente en un portal corporativo.

Partimos del requerimiento de que tenemos una página de SharePoint con un webpart de tipo biblioteca de documentos. En concreto se trata de una biblioteca de Currículums Vitae en el que cada usuario solo ve sus currículos y versiones del mismo en diversos idiomas. Lo que queremos conseguir es que si un usuario lleva más de 5 meses sin actualizar uno de sus CV’s, este se ponga a “parpadear” en rojo chillón y aparezca un mensaje del tipo “¡¡Actualízame ya!!”. Como comprenderéis, si os pasan un requerimiento similar, difícilmente lo podréis implantar sin el uso de código, y lo cierto es que el ejemplo viene que ni pintado para el uso de javascript.
Los pasos que vamos a seguir son:
  1. Definir un estilo para el parpadeo
  2. Obtener la fecha actual y darle un formato que permita compararse con otra fecha
  3. Buscar los valores de la columna de tipo fecha a comparar en el WebPart específico
  4. Para cada uno de los resultados (ficheros):
    1. Darle un formato a la fecha permita compararse con la fecha actual
    2. Restar la fecha actual con la fecha de modifiación
    3. Pasar el resultado a días
    4. Si los días superan los requeridos (en el ejemplo 150), asignar el estilo “parpadeo” al elemento y añadirle un aviso.
Antes de empezar debéis aseguraros de tener jquery subido como fichero en alguna biblioteca documental del SharePoint, por ejemplo en “/SiteAssets/”. Jquery lo podéis descargar de forma totalmente gratuita aquí.

Lo siguiente será ir a la página de SharePoint que contenga nuestro WebPart y añadir un WebPart de Script Editor que encontraremos en la categoría de “Media and Content”. Este WP será una tontería, pero a mí me tiene loco en 2013 y creo que es el que más uso para ir compensando “alguna que otra” carencia de SP 2013…

image

Seguidamente, iremos al WebPart recién añadido y pulsaremos en “Edit snippet” para añadir el código deseado en la página.

image
Una vez puestos en situación, vamos a empezar definiendo un style de CSS que permita visualizar su contenido en forma de parpadeo. Comentar aquí que algún navegador como firefox no aceptaba antes del CSS3 el estilo “animation”, así que usaremos aquí el –webkit-animation-duration de CSS. Para navegadores con CSS2 usaremos el animation, pero será inevitable que en algunos (firefox antiguos, por ejemplo) no funcione.

<style>
    @keyframes blink {from { opacity: 1.0; }  to { opacity: 0.0;}}
    @-webkit-keyframes blinker {from { opacity: 1.0; }  to { opacity: 0.0;}}
    .parpadeo{
         color: red;
         font-weight: bold;
         -webkit-animation-name: blinker; 
         -webkit-animation-iteration-count: infinite; 
         -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
         -webkit-animation-duration: 1s;
         animation: blink 1s steps(2, start) infinite;
    }
</style>


Evidentemente, podéis sustituir tranquilamente el “color:red” por el color que más os apetezca.
A continuación hacemos la invocación a jquery, cambiando la URL relativa por aquella en la que tengais cargado vuestro fichero jquery, y indicando la versión que ser corresponda con la vuestra.
<script type="text/javascript"  src="/SiteAssets/jquery-1.11.1.js"> </script>
iniciamos ya nuestro script de javascript definiendo una función que se ejecute justo después de que se carguen todos los elementos de la página (es importante, ya que de lo contrario podría ser que el script todavía no encontrara los elemento estamos referenciando).

<script type="text/javascript">
    $(document).ready(function() {

Lo primero que vamos a hacer en nuestra función es obtener la data actual, y darle el formato apropiado para poder compararla con la fecha de modificación del fichero.

        var TodayFull= new Date();
        var Today = TodayFull.getDate()+ "/" +(TodayFull.getMonth() +1) + "/" + TodayFull.getFullYear();
        var TodaySplit = Today.split('/');
        var TodayDate = Date.UTC(TodaySplit [2],TodaySplit [1]-1,TodaySplit [0]);

Un vez hecho esto el siguiente paso es obtener la fecha de modificación de cada CV (pueden haber múltiples). Para ello hay que encontrar una forma única de identificar el campo “Modified” que contiene la fecha de la última modificación del fichero. Aquí os recomiendo que tiréis del F12 y en el panel de Developer Tools, mediante la herramienta de selección de elementos...

image

...y pulséis encima del campo de fecha que os interese, (en mi caso “Modified”) y observéis si dicho campo (o alguno de sus “padres”) contiene una clase o id que os sirva para identificarlo de forma concreta.
image

En este caso vemos que la fecha se contiene en un ‘span’ que está dentro de un ‘td’ con un estilo ‘td.ms-vb-lastCell’. En este caso, la siguiente sentencia servirá para obtener todos los campos ‘Modified’ del WP con título “KEEP YOUR CV UPDATED”. Tened en cuenta que en mi ejemplo tan solo hay una columna de tipo fecha. En caso de existir múltiples de ellas, posiblemente tendríamos que afinar más la siguiente línea a fin de asegurarnos de que atacamos el campo que queremos comparar y no otra fecha existente en el listado.

$("span:contains('KEEP YOUR CV UPDATED')").parent().parent().find('td.ms-vb-lastCell span').each(function(index) {

Por favor, sustituid los parámetros de nombre del WP y nombre del campo por los vuestros propios para que os funcione correctamente. Quizás a algunos les pueda resultar un tanto compleja, así que paso a explicarla por partes:

$("span:contains('KEEP YOUR CV UPDATED')") –> Nos sitúa dentro del WP con ese título. Sustituidlo por el nombre de vuestro propio WP

.parent().parent() –> Nos sitúa en el <div> que contiene todo el código del WP, para poder seguir buscando nuestra columna “Modified” (el span anterior no la contenía).

find('td.ms-vb-lastCell span') –> Nos sitúa sobre los diversos valores del campo Modified (contiene todos los ficheros existentes).

each(function(index) { –> Para cada uno de los valores retornados (cada fichero), ejecutamos la siguiente función

El siguiente paso (a partir de aquí ya lo haremos para cada uno de los ficheros a comprobar), será aplicar el mismo procedimiento a la fecha obtenida por el campo Modified que el que le hicimos pasar a la fecha actual. Transformamos el campo en el formato adecuado para la comparación entre fechas:           
            var Modified = $(this).html().substring(0,10);
            var ModifiedSplit = Modified.split('/');
            var ModifiedDate = Date.UTC(ModifiedSplit [2],ModifiedSplit [1]-1,ModifiedSplit [0]);

Ahora ya estamos en disposición de restar directamente la fecha de hoy con la de creación del documento:

var dif = TodayDate - ModifiedDate;

El resultado obtenido tenemos que convertirlo a días mediante la siguiente fórmula:

var dias = Math.floor(dif / (1000 * 60 * 60 * 24));

Ahora ya podemos establecer la causa condicionas, indicando lo que vamos a hacer si han pasado x días (en mi caso 150, pero sustituidlo por vuestro propio valor)

if (dias >150) {

Cuando un documento esté "caducado", primero vamos a hacer que aparezca parpadeando, asignándole el estilo que creamos para ello:

$(this).addClass("parpadeo");

También, opcionalmente, podemos agregar un comentario para hacer todavía más llamativa la urgencia de actualizar el fichero:

$(this).append ( "¡¡UPDATE NOW YOUR CV!!");

¡Y ya solo nos queda cerrar el condicional, cerrar la función del each, la función principal y el tag de script!
            }
        });
    });
</script>

 Como resumen, el código debería haber quedado muy similar al siguiente (modificando el nombre del WebPart y los días necesarios para considerar un documento caduco).

<style>
    @keyframes blink {from { opacity: 1.0; }  to { opacity: 0.0;}}
    @-webkit-keyframes blinker {from { opacity: 1.0; }  to { opacity: 0.0;}}

    .parpadeo{
         color: red;
         font-weight: bold;
         -webkit-animation-name: blinker; 
         -webkit-animation-iteration-count: infinite; 
         -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
         -webkit-animation-duration: 1s;
         animation: blink 1s steps(2, start) infinite;
    }
</style>

<script type="text/javascript"  src="/SiteAssets/jquery-1.11.1.js"> </script>
<script type="text/javascript">
    $(document).ready(function() {
        //obtenemos la fecha actual y le damos el formato adecuado para poderla comparar
        var TodayFull= new Date();
        var Today = TodayFull.getDate()+ "/" +(TodayFull.getMonth() +1) + "/" + TodayFull.getFullYear();
        var TodaySplit = Today.split('/');
        var TodayDate = Date.UTC(TodaySplit [2],TodaySplit [1]-1,TodaySplit [0]);
        //obtenemos la fecha del campo mostrado en pantalla y le damos el formato adecuado para poderla comparar
        $("span:contains('KEEP YOUR CV UPDATED')").parent().parent().find('td.ms-vb-lastCell span').each(function(index) {
            var Modified = $(this).html().substring(0,10);
            var ModifiedSplit = Modified.split('/');
            var ModifiedDate = Date.UTC(ModifiedSplit [2],ModifiedSplit [1]-1,ModifiedSplit [0]);
            //comparamos las 2 fechas obtenidas
            var dif = TodayDate - ModifiedDate;
            //pasamos el resultado a días reales
            var dias = Math.floor(dif / (1000 * 60 * 60 * 24));
            if (dias >150 {
                $(this).addClass("parpadeo"); //asignamos el style definido de parpadeo
                $(this).append ( "¡¡UPDATE NOW YOUR CV!!"); //añadimos una frase con 'gancho' para atraer la atención del usuario
            }
        });
    });

</script>
Veremos que si tenemos, por ejemplo, 2 documentos desactualizados, el resultado que veríamos en pantalla sería algo parecido a lo siguiente:

image

En el momento que actualicemos uno de ambos documentos, el estilo aplicado sería el normal y veríamos algo similar a lo siguiente:

image

El script que he insertado de demostración, debería valer para cualquier página, únicamente modificando el nombre del WebPart. Eso sí, tened en cuenta que podría no funcionar en listados con más de un campo de tipo fecha (se debería afinar en ese caso la localización de la columna específica a comparar) y exploradores sin CSS3 o que no admitan el estilo ‘animation’ (caso de firefox antiguos, por ejemplo).

El texto parpadeando puede parecer muy "retro" y típico de las webs de los años 90, pero en determinados casos, cuando el usuario ve en rojo chillón parpadeante que tiene que actualizar un documento, tenemos más probabilidades de que decida actualizarlo... ¡¡Al menos eso quiero creer!!

Pues nada más por hoy Sharepointer@s, es posible que en el futuro vuelva a postear un ejemplo práctico de aplicación del JavaScript en el SharePoint... aunque, ¡Cuidado! ¡¡Al final uno le puede coger el gusto y hay que controlarse para no meterlo en todas partes!!

;-D


viernes, 31 de octubre de 2014

Cómo saber qué plantilla de sitio está usando SharePoint usando únicamente el explorador

¡Buenos días a tod@s!

Tras un largo periodo de inactividad en el blog forzado por el alto estrés laboral/familiar voy a ver si consigo ponerme de nuevo en sintonía empezando hoy por un post sencillito donde explico cómo saber qué plantilla de sitio se está usando en un site específico de SharePoint (testeado en 2010 y 2013); esto puede ser muy útil cuando nos pasan un proyecto o una plantilla en la que no hemos colaborado desde el principio y queremos saber rápidamente en base a qué plantilla se ha construido el portal (para crear un paquete de despliegue del mismo, por ejemplo).

Para saber la plantilla de sitio utilizada en SharePoint, bastará con seguir los siguientes pasos:

1.- Ir a cualquier página del sitio que queramos saber su plantilla y con el botón derecho del ratón pulsar en cualquier zona de la pantalla y seleccionar "Ver código fuente"

2.- En el código buscar el valor de la siguiente variable: g_wsaSiteTemplateId


En este ejemplo el valor es "BLANKINTERNET#0"

3.- Buscamos en un listado de default site templates (clic aquí) para encontrar su correspondencia con el nombre conocido de la plantilla.

Veremos que en nuestro caso

BLANKINTERNET#0 se corresponde con una plantilla de "Publishing Site"


Si el valor de la variable g_wsaSiteTemplateId  hubiera sido 'STS#1', en el listado veríamos que se corresponde a un "Blank Site" y así para cualquier valor posible de dicha variable.

Ya sabemos pues a que tipo de site nos enfrentamos, así que ahora será más fácil dominarlo...

¡Salud!

viernes, 20 de junio de 2014

Importar un Term Set directamente desde un fichero .csv

Todos los que hayáis estado trabajando con metadatos administrados, es muy probable que en algún momento os hayan hecho la misma pregunta: “¿Existe algún tipo de fichero que yo pueda trabajar a mano y que posteriormente sirva para crear automáticamente el árbol de metadatos?” La respuesta en este caso es “sí”, aunque, por supuesto, tiene sus limitaciones:

Una de las limitaciones importantes es que solo se puede gestionar un Term Set (conjunto de términos) por fichero. Es imposible crear todo un Grupo de Términos. Así que si tienes 10 conjuntos de términos, tendrías que gestionar 10 ficheros .csv distintos.
image
Otra “limitación” muy importante es la excesiva rigidez del formato del fichero, que debe ser exactamente tal y como establece Microsoft. Si se te escapa una coma o pones mal un nombre de columna, la importación fallará y tendrás que revisar que el fichero sea estrictamente correcto.

En este post explicaré qué pasos seguir para importar correctamente un Term Set a partir de un fichero Excel.

Lo primero es generar un documento Excel en blanco, y crear columnas con los siguientes titulares:
  • Term Set Name: En la segunda fila de Excel especificaremos el nombre del conjunto de términos.
  • Term Set Description: En la segunda fila del Excel especificaremos la descripción del conjunto de términos.
  • LCID: (Dejar en blanco)
  • Available for Tagging: Incluir un “TRUE” en cada fila si queremos que el término esté disponible para usar desde la interface de las listas de SharePoint.
  • Term Description: Establece la descripción (opcional) de cada término
  • Level 1 Term: Nombre del primer nivel del término. A repetir para cada término de nivel inferior existente.
  • Level 2 Term: Nombre del segundo nivel del término. A repetir para cada término de nivel inferior existente.
  • Level 7 Term: Nombre del séptimo nivel del término.
Como ejemplo gráfico, nos debería quedar un Excel del siguiente estilo:
image
Es importante que entre los literales que introduzcáis en las celdas del documento no introduzcáis ninguna coma ni punto y coma, pues os puede jugar una mala pasada en la importación. Os recomiendo que si tenéis alguna coma del tipo “Rioja, La” hagáis una transformación previa (find & replace) del tipo “Rioja (La)”. De esta forma os asegurareis que no tendréis ningún problema en la importación.

Así pues, una vez tengamos todo el excel construido por completo según nuestra especificación, lo guardaremos como .csv

image
Una vez hecho esto, cerraremos nuestro cliente Excel, y abriremos el fichero desde nuestro querido Notepad.

Desde Notepad, lo primero que haremos será volver a “guardar como”, y esta vez guardaremos el fichero en formato “UTF-8” (en caso contrario tendremos un desaguisado con acentos y demás caracteres especiales).
image
Una vez guardado como .csv UTF-8, ya solo queda sustituir TODOS los puntos y coma del fichero por comas simples. Como comenté, el formato SharePoint es muy rígido y solo admite .CSV separados por comas.
image
En el supuesto caso que en alguno de los literales del Excel os hubierais descuidado alguna coma (por ejemplo “Rioja, La”) veréis que os lo importa en un nivel adicional (Nivel 2: “Rioja”, Nivel 3: “La”), es por eso que tenéis que vigilar de que no quede ninguna coma antes de guardar el Excel como .csv.
Y, ahora sí, estamos listos para importar. Vamos al servicio de metadados administrados, nos situamos en el Grupo donde queramos importar el Term Set, abrimos el menú desplegable con el botón derecho del ratón y seleccionamos “Import Term Set”
image
Seleccionamos el fichero .csv que hemos preparado, pulsamos OK…
image
… ¡¡Y listo!!
image
De esta forma podríamos ahorrarnos tener que teclear uno a uno los términos por el árbol de metadatos (Los datos iniciales del Excel podríamos obtenerlos de diversas fuentes externas sin necesidad de introducción manual).

Por cierto, si quisierais realizar la operación contraria (Exportar el árbol de metadatos a un fichero Excel para su revisión externa al servicio), tendríamos que realizar los pasos inversos. La exportación se debería realizar mediante PowerShell (curiosamente no hay un “export” en la SharePoint Interface), y luego sustituir las comas por puntos y coma desde el Notepad antes de abrirlo en Excel.

Y ya con esto… ¡¡Hasta la próxima!!

miércoles, 18 de junio de 2014

SPD 2013: Utilizar una columna de “metadatos administrados” en un Workflow.

Cuando nos enseñan a crear metadatos administrados (Managed Metadata) en SharePoint 2010 y 2013, vemos que es un servicio muy “cool” y tendemos a recibirlos con gran entusiasmo y a querer incorporarlos asiduamente a nuestra “familia” de tipos de columnas que nos gusta administrar en nuestro SharePoint.

Sin embargo, el tiempo y la experiencia nos demostrará que este tipo de columnas no son tan amigables como nos gustaría, y tiene una serie de limitaciones importantes (alguna ya resuelta en 2013, y otras que faltarían en esa lista).

En concreto hoy voy a centrarme en cómo utilizar este tipo de campos en los flujos de trabajo que utilizaremos en SharePoint Designer, pues no es tan sencillo como debiera ser o pudiera parecer (¡Esto es SharePoint, amigos!).

Vamos a partir del siguiente ejemplo/requerimiento: Tenemos una biblioteca de SharePoint donde existe una columna de tipo “metadatos administrados” de dos niveles. El primer nivel nos indica la provincia. El segundo nivel el municipio. La función de este campo es que el usuario pueda marcar la relación directa de un Municipio con su Provincia, de igual forma que haríamos con un desplegable en cascada. El campo almacena toda la ruta en sí mismo (ambos niveles), para que sea visible la relación existente a simple vista y el workflow pueda tratarlo.

El campo tendría el siguiente aspecto:
image
Ahora vamos a desarrollar un flujo de trabajo que permita leer ese valor y utilizarlo para separarlo en 2 metadatos diferentes (Provincia y Municipio), ya que eso permitirá al usuario filtrar u ordenar por ambos conceptos.

Lo primero que alguien normal intentaría sería realizar algo del tipo: Crear una variable tipo String y guardar en ella el valor de la columna.

image

Si hacemos esto tal cual, veremos que obtenemos un error en el flujo donde nos indica que no puede convertir en string este tipo de dato:

System.InvalidCastException: The value 'd/results(0)/Localidad' cannot be read as type 'String'.
Lo siguiente sería darnos cuenta de que al crear el managed metadata “Localidad”, automáticamente se ha creado un campo “Localidad_0” que invocado desde el flujo permite modificar lo que retorna a “Texto plano”.

image

Si lo intentamos de esta forma no nos dará un error, pero el valor retornado será un galimatías indescifrable del tipo “Calella|685929bb-f430-4179-9302-5c7fb646f5ac”. Si únicamente es un nivel, podemos hacer un “substring” del resultado, y quedarnos con la primera parte del “churro que retorna” (a partir del separador “|”). En el caso de que estemos trabajando con varios niveles de anidación, como en nuestro ejemplo, la estructura retornada del tipo “valor del último nivel de tag|GUID”  ha perdido todos los valores de los primeros niveles del árbol de metadatos, y no nos permite recuperar el string deseado, del tipo "Barcelona:Calella".

¡Maldito bicho! ¿Cómo podemos tratarlo entonces? Pues si nuestro flujo está en modalidad 2013 podremos hacerlo mediante la invocación y tratamiento del WebService que nos va a devolver el valor deseado del ítem tratado en la lista. (aquí es cuando comienzas a arrepentirte de no haber utilizado un “cascading dropdown” eh! Guiño). Tranquilo… respira… Aquí la solución:

El primer paso será crear una variable de tipo diccionario, mediante la acción “Build Dictionary” que encontraremos en la sección “Core Actions”, donde añadiremos 2 campos, uno llamado “Accept” y otro llamado “Content-Type”, ambos de tipo String, y ambos con el mismo valor: “application/json;odata=verbose”
image

Una vez inicializada esta variable, procederemos a invocar el WebService. Hay que tener en cuenta que el WebService a utilizar será del tipo:

Current Site URL/_api/Web/Lists('List GUID')/Items(Current ID)/ManagedMetadataName/Label
Para ello recurriremos a la acción “Call HTTP Web Service” que encontraremos en la sección “Core Actions”. Una vez insertada, modificaremos el parámetro “this” por la siguiente cadena (contiene 3 referencias a propiedades dinámicas)

[%Workflow Context:Current Site URL%]/_api/Web/Lists(guid'[%Workflow Context:List ID%]')/Items([%Current Item:ID%])/Localidad/Label

Donde modificaremos "Localidad" por el nombre de nuestro metadato administrado.

También modificaremos el parámetro “response” por una nueva variable de tipo “Dictionary”. Esta variable almacenará el resultado de la llamada al WebService.
image
Una vez realizada la invocación al WS, es un momento estupendo para insertar un log de control en el flujo y ver qué ha respondido el servicio. Para ello utilizaremos la acción “Log to History List” que encontraremos en el grupo de “Core Actions”.
image
Ahora vamos a extraer del xml retornado el valor en formato string del campo de managed metadata.

Para ello utilizamos la acción “Get an item from dictionary” en el grupo de “Core Actions”. Aquí sustituiremos los 3 parámetros:
  • item by name or path: Directamente por “d/Label”
  • dictionary: La variable de tipo Dictionary donde hemos guardado el resultado de la invocación al HTTP Web Service.
  • item: Nueva variable de tipo String donde almacenaremos el valor literal del campo.
image
Opcionalmente podemos insertar en este punto otro “Log to History List” para comprobar el valor convertido en String.

image
Llegados a este punto ya tendríamos el valor del campo de metadatos administrados en formato String, conservando todo su path de niveles de anidación.

A partir de aquí haremos el proceso de datos que queramos con este string. En nuestro ejemplo queríamos almacenar cada parte del mismo en un campo distinto, así que vamos a ello.

Para saber en qué posición se encuentra el separador de nivel del árbol de metadatos (en SharePoint 2013 son los dos puntos ‘:’) utilizaremos “Find substring in string” de la sección “Utility Actions”.
  • substring: Poner directamente los 2 puntos ‘:’
  • string: indicar la variable donde almacenamos el resultado del “Get an Item from dictionary”
  • Variable: index:  Podemos dejarla la que inserta SPD por defecto, es una nueva variable de tipo integer que indicará en qué posición se encuentra el separador.
image
Ahora utilizaremos la función “Extract Substring from Start of String” de la sección de “Utility Actions” para obtener el primer valor del campo de metadatos administrados, contenido entre el inicio del string y los dos puntos.
  • 0: Substituir por la variable de tipo integer que obtuvimos como resultado de la búsqueda del patrón en “Find substring in string”
  • string: Indicar la variable donde almacenamos el resultado del “Get an Item from dictionary”
  • Variable: substring: Nueva variable de tipo string que almacenará el primer nivel del arbol del campo de metadatos administrados. En este ejemplo, contendrá el nombre de la provincia.image
Ahora deberemos incrementar el índice en una unidad para saltarnos el separador (‘:’) y posicionarnos en el primer carácter del segundo string. Para ello utilizaremos la acción “Do calculation” que se encuentra en el grupo “Core Actions”.
  • value:Substituir por la variable de tipo integer que obtuvimos como resultado de la búsqueda del patrón en “Find substring in string”
  • plus: Dejarlo en “plus” exactamente igual como nos aparece inicialmente. Hará una suma.
  • value: Indicar una unidad, que es lo que queremos sumarle al índice. ‘1’.
  • Variable: calc: Nueva variable de tipo Number que se genera como resultado del cálculo. Podemos dejarla tal cual aparece por defecto
image
Ahora utilizaremos la acción “Extract Substring from Index” del grupo “Utility Actions” para obtener el segundo valor contenido entre el carácter posterior a los dos puntos y el final del string.
  • string: Indicar la variable donde almacenamos el resultado del “Get an Item from dictionary”
  • 0: Substituir por la variable de tipo number que obtuvimos en el resultado de “Do Calculation”
  • Variable: substring: Nueva variable de tipo String que almacenará el segundo nivel del metadato administrado. En nuestro ejemplo será el Municipio.
image
En este punto ya tenemos separados ambos valores del campo de metadatos administrados (Provincia y Municipio). De forma opcional, podríamos indicar estos valores en el “history list”. Ahora solo quedaría introducir esos valores en las columnas correspondientes de la biblioteca. Para ello usaremos la acción “Update List Item” que encontraremos en grupo de “List Actions”.
image
Hecho esto nuestro flujo ya debería funcionar perfectamente. Tendría un aspecto similar al siguiente:
image
Ya solo quedaría publicar y listo. Una vez lo hayamos hecho ya solo quedará montarnos las vistas en la biblioteca según nuestro criterio para mostrar los datos requeridos. A pesar de que en el NewForm.aspx el campo que aparece es el de “Localidad” de tipo Managed Metadata, en las vistas podremos jugar con los campos “Provincia” y “Municipio” de tipo string que nos alimentará el workflow:
image
Notad que para este ejemplo he usado un metadato administrado de 2 niveles, pero podrían ser muchos más igualmente. La clave está en usar la llamada http al WebServices para obtener el String resultante.

Como veis, es mucho más simple un cascading dropdown, que francamente, os lo recomiendo antes que realizar todo este proceso. Sin embargo, los requerimientos del cliente vienen como vienen, y no siempre tenemos la opción de plantear la mejor arquitectura técnica.

¡¡Saludos SharePointeros!!

jueves, 12 de junio de 2014

¿Formularios en SharePoint? Un momento, por favor... (necesito pensar)


A estas alturas ya sabemos todos que Microsoft ha “condenado a muerte” a Infopath. A pesar de que le hicieron un “entierro” simbólico en la pasada SharePoint Conference, el soporte oficial está garantizado hasta el año 2023, un nuevo sustituto está cocinándose a fuego lento (una primera versión debería estar lista a finales de verano), y algunas alternativas han sido presentadas para ir paliando las necesidades actuales. Sin embargo son tiempos confusos para el “hacedor” de formularios en SharePoint. Si te sientes perdido, si dudas entre usar Infopath u otra alternativa… hoy voy analizar todas ellas, y a dar mi humilde opinión personal al respecto.

Ya lo anunció Microsoft en su conferencia: Esto es un viaje (largo) y todavía no hay un sustituto de InfoPath. Sin embargo, todos conocemos ya (y hemos sufrido) las limitaciones de InfoPath. Está claro que necesitaba un relevo de nuevo formato, integrado con SharePoint, más intuitivo, ágil y dinámico que construya un código HTML limpio y optimice el rendimiento de la renderización y comunicación de los formularios. Solo por emprender este viaje, mis respetos y mis aplausos hacia Microsoft.

También es muy buena señal que Microsoft inicie el viaje con total transparencia y solicitando el feedback y colaboración de la comunidad de SharePoint. Dicen que nos van a tener en cuenta para tomar decisiones en la arquitectura y el roadmap del FoSL, lo cual sería realmente de muy buen hacer y agradecer.

Sin embargo, al mismo tiempo tenemos la bomba sobre la mesa: Nuestros clientes nos siguen pidiendo la implantación de procesos empresariales que requieren de formularios repletos de lógica de negocio y un nivel de complejidad a tener en cuenta. ¿Qué hacemos ahora? ¿Les seguimos implantando InfoPath a riesgo de que en un plazo corto de tiempo consultorías externas puedan tacharnos de implantar soluciones "deprecated" o en desuso? ¿Los convencemos de que prioricen otro tipo de proyectos hasta que llegue FoSL? ¿Les desarrollamos custom forms a pesar de que siempre nos ponen la premisa del uso de componentes Out Of The Box?

Vamos primero a analizar el abanico de opciones disponible y el que está por venir, y finalmente podremos sacar algunas conclusiones.

Formularios de lista
Los formularios de lista que vienen incluidos de forma estándar en SharePoint son viejos conocidos por todos nosotros. Ofrecen la base sobre la cual podemos construir cualquier aplicación en SharePoint, pero tienen muchísimas carencias, tales como la imposibilidad de mejorar su diseño (si no es con Infopath), la carencia de estructuras de repetición, la limitación de un campo por cada fila, la imposibilidad de añadir cualquier tipo de lógica de formulario (excepto campos obligatorios y validaciones simples de valores introducidos). Por la integración nativa que tienen con SharePoint, su velocidad de respuesta, la sencillez de su creación y la total garantía de que lo que construyamos con ellos serán fácilmente migrables a cualquier versión posterior de SharePoint, son ideales para formularios sencillos y siempre deben utilizarse si los requerimientos son sencillos y nos lo permiten, sin embargo suelen ser insuficientes cuando los requerimientos se vuelven algo más exigentes y complejos. Está claro que todo esto cambiará cuando llegue FoSL y el nuevo editor de formularios esté igualmente integrado a un simple click del botón "Custom Form" de la Ribbon.

Infopath
Hasta ahora era la solución habitual para resolver aplicaciones de negocio de relativa complejidad siempre y cuando no quisieras a entrar a desarrollar formularios con Visual Studio y código personalizado (una opción muy válida y ciertamente recomendable en la mayoría de escenarios). Es cierto que durante años hemos sufrido sus carencias y sus defectos, entre los más sonados la complejidad del código que genera al renderizarse como HTML, la lentitud de respuesta en formularios pesados, la dificultad para añadir código personalizado en el interior del formulario o la escasa evolución del mismo en el transcurso de los años. Sin embargo es una solución muy válida para muchos escenarios en los que el volumen de solicitudes no sea demasiado alto o la complejidad del formulario no sea excesiva (excesivas llamadas a fuentes externas darían como resultado un formulario de extrema lentitud de carga, por ejemplo). A su favor cuentan la relativa facilidad para incluir mejoras en el diseño (fondos, tablas, imágenes, redimensión de campos...) y la notable variedad de campos y lógica que le podemos añadir (repeating tables, botones de imagen, secciones...). Sin embargo la sentencia a muerte de Microsoft va a hacer que cada vez se desaconseje más su uso, pues pese a que han asegurado soporte a Infopath hasta 2023, elaborar hoy aplicaciones con una aplicación que se sabe que estará "deprecated" en breve va a salir en amarillo tirando a rojo en cualquier auditoría que nos hagan a partir del 2015. Es por eso que deberíamos evitarlo de ser posible de ahora en adelante, e intentar implantar algún tipo de solución alternativa.

Encuestas de Excel
Tal y como comenté en un post anterior, las encuestas de Excel (Excel Surveys) no son un editor de formularios para aplicaciones de negocio. Únicamente permiten crear (de forma muy rápida y sencilla, eso sí), encuestas que puedes compartir de forma inmediata con personas de todo el mundo simplemente a través de una URL de internet. Las respuestas creadas por los usuarios serán almacenadas en el interior del propio Excel. Es un producto independiente de SharePoint y no puede vincularse ni a sus listas ni a sus flujos de trabajo. Además, las encuestas son extremadamente sencillas y no permiten lógica, ni cambios en el diseño (muy básico) o tipos de campos complejos. Tampoco permite establecer ningún tipo de seguridad: Cualquier persona que acceda a la URL de la encuesta podrá contestarla. Por todos esos motivos, y sobre todo porque "encuesta" no es lo mismo que "formulario de negocio" descartamos esta solución como posible para nuestros requerimientos de implantar formularios de cierta entidad en un cliente para una granja SharePoint.

Documentos estructurados
Realmente se explicó muy poco sobre ellos, así que todavía se sabe a penas nada. Se supone que será una alternativa a los documentos en PDF, que se podrá realizar con Word. Imaginaos pues un documento tipo "plantilla" de Word, con una serie de metadatos que se repiten por el contenido del mismo. Los documento se almacenarán en bibliotecas de SharePoint y los metadatos podrán rellenarse desde el propio SharePoint sin tener que entrar en el Word. Es cierto que esto ya puede hacerse actualmente asignando una plantilla de Word a un Tipo de Contenido, pero se van a incluir nuevas funcionalidades para que no tengas que volver a pensar en los formularios tipo "PDF".

Por lo tanto, se perfila como un tipo de formulario pensado más para imprimir o conservar en "formato tipo papel", pero no lo veo integrándose en procesos empresariales con flujos de trabajo y vistas dinámicas o lógica de campos. Será algo más "simple" y "robusto", que vendrá bien para casuísticas muy concretas (plantillas de contratos de confidencialidad, por ejemplo).

Formularios Access (App Forms)
Los formularios que se pueden hacer con Access Services 2013 suelen ser un gran desconocido por la mayoría, seguramente por el anacronismo que la propia palabra "Access" nos provoca en el subconsciente. Todos pensamos en Access como algo del pasado remoto, y sin embargo es cierto que en la versión 2013 Microsoft ha conseguido con Access un editor web robusto y potente de formularios que gestionan tablas relacionales. Prueba de ello es que parte del editor del formulario de Access Services formará parte de la nueva arquitectura de FoSL. De todas las alternativas que Microsoft ha presentado para sustituir Infopath, esta sería una de las más válidas, aunque tiene una gran limitación: No puede participar en procesos de negocios (WorkFlows) porque los datos se almacenan directamente dentro de la propia base de datos Access. Es un formulario imbuido en el propio Access, por lo tanto no es válido para escenarios donde tengamos que interactuar con SharePoint, flujos de trabajo, formularios... pero es perfectamente válido para cuando lo único que necesitemos sea generar bases de datos relacionales y formularios para su manejo. Un buen ejemplo sería la gestión (a nivel informativo) de un inventario de productos. Hay que tener también en cuenta que la seguridad es a nivel de acceso al formulario (quien puede verlo, utilizarlo o administrarlo), pero no permite indicar quien puede acceder o no a determinadas vistas o campos (no hay más posibilidades de configurar la seguridad una vez estás dentro del formulario).

FoSL (Forms over SharePoint Lists)
Sobre el papel, es el futuro, la "tierra prometida" que debe fusionar aspectos básicos como:
  • Integración nativa de los formularios de listas de SharePoint
  • Flexibilidad en diseño (drag & drop, resize directo de los campos, situar campos donde arrastre el puntero...)
  • Interface moderna (HTML5), ágil y sencilla de utilizar
  • Lógica de campos, reglas y formato condicional incluido
  • Acceso a fuentes externas de datos (no en la primera versión)
  • Estructuras de repetición (no en las primeras versiones)
Aun así, seguro que no llega a ser tan fantástico ni tan potente como los productos que han desarrollado las grandes compañías de terceros, porque si no... ¿De qué vivirían esos partners de Microsoft? Hay que seguir alimentando el ecosistema, y estoy convencido que seguirá siendo así en todos y cada uno de los aspectos de las nuevas versiones que SharePoint nos siga brindando. Así que tendremos que estar atentos a las limitaciones y al roadmap de features que irán entregando para saber del cierto hasta dónde llega FoSL. De momento no existe y la primera experiencia será seguramente a finales de verano (¿septiembre? ¿octubre?) cuando lo incorporen en un upgrade de SharePoint Online.

Custom code (HTML5, aspx...)
Sin duda es una de las grandes soluciones a tener en cuenta, siempre y cuando nuestro cliente no ponga impedimentos al desarrollo personalizado con Visual Studio (hay que tener en cuenta que en una migración a versión posterior lo primero que suele decir Microsoft es que sólo garantizan la correcta migración del "out of the box").

Los límites funcionales desaparecen cuando desarrollamos nosotros los formularios, pues carecemos de las limitaciones de un servicio o aplicación ya construidos, y en función de las horas asignadas para el desarrollo, podremos crear formularios más o menos espectaculares. Sin embargo requeriremos depender de un equipo técnico altamente especializado para su desarrollo (programadores). Para crear nuestras páginas aspx personalizadas podemos recurrir a diversos recursos, aunque conociendo que FoSL tendrá un alto componente de HTML5, puede que este sea una buena opción de cara a una futura compatibilidad/migración de nuestro formulario.

 Software de terceros
Esta es una solución que nos hace plantear profundamente cuestiones existenciales del tipo. ¿Por qué si este partner ha podido desarrollar este diseñador de formularios tan fantástico Microsoft no puede (o no lo "compra y fagocita")? (aunque ya me he respondido a mí mismo en la sección de FoSL). Si has tenido la suerte de poder trabajar con soluciones de terceros tipo Nintex Forms o Infowise ultimate forms, sabrás a lo que me refiero: Interface ágil e intuitiva integrada en el navegador, todo tipo de campos, lógica, reglas, formato condicional, diseño libre, pestañas, estructuras de repetición, código limpio, ejecución rápida... En fin, todo lo que podamos pedir, que además se irá actualizando periódicamente con nuevas funcionalidades y bugfixing si tenemos contrato de mantenimiento contratado. El gran contra, claro está es el elevado coste del licenciamiento de este tipo de soluciones, así como el no tener una respuesta clara a la pregunta ¿Qué pasará con todos estos formularios cuando migre a SharePoint 2016? Seguro que si has contratado alguna de las grandes mencionadas, habrá continuidad de versión y herramientas de migración, pero a un coste adicional. Además, aquí en España no somos muy partidarios de vincularnos hasta la eternidad con un partner de servicios.

 Conclusiones
El futuro está claro que es de FoSL. El resto es pirotecnia de distracción. La teoría nos dice que tendrá todo lo que realmente estábamos deseando como sustituto perfecto de InfoPath, ya que tendrá una interface intuitiva integrada con el navegador, mezclando la Ribbon con paneles laterales de detalles y motor de construcción de formularios de Acces Services, que evitarán la ejecución de cualquier software ajeno al navegador. Permitirá también un diseño fluido, con drag & drop, poder situar los componentes allá donde los "soltemos", redimensionarlos al gusto, e incluir lógica, reglas, formato condicional, invocación a datos externos, estructuras de repetición... eso sí, dichas funcionalidades irán saliendo en cuentagotas con diversas versiones, y puede pasar todavía mucho tiempo hasta que podamos hacer una repeating table con FoSL. Seguro que tiene limitaciones funcionales, como suele ser habitual en el mundo SharePoint: Microsoft te da hasta cierto punto y más allá necesitas la ayuda de un developer/proveedor/software de terceros. La gran pega es que actualmente no existe y no hay datas claras sobre su disponibilidad.
Así que mientras tanto, hay diversos escenarios que hay que tener en cuenta:
  • ¿El cliente tiene ya una solución de terceros / puede encajar su instalación? (asumiendo presupuesto de licenciamiento, costes de migración a futuras versiones asumido y no reticencia a la dependencia de terceros) = Soluciones de terceros como Nintex Forms o Infowise ultimate forms.
  • ¿El cliente acepta que se desarrolle código personalizado en SharePoint? (asumiendo posibles costes de migración a futuras versiones y costes de desarrollo) = Formularios con desarrollo personalizado (HTML5 o ASP.NET)
  • ¿Los formularios no forman parte de ningún flujo de trabajo y trabajan meramente con datos relacionales de fuentes de datos externas o tablas? = Access Services
  • ¿Los requerimientos funcionales y de diseño son suficientemente sencillos como para ser implantados por formularios estándar de SharePoint? = Formularios de lista
  • ¿El cliente tiene SharePoint Online y el proyecto puede empezar a partir de septiembre/octubre 2014? Podemos arriesgarnos a ser los primeros en usar FoSL (aunque sabemos que será una versión básica).
  • ¿Ninguna de las anteriores? Ya solo nos queda el "viejo y moribundo" Infopath... aunque en este caso el cliente agradecerá nuestra preocupación y honestidad al aclarar nuestra inquietud por usar una tecnología que en pocos años estará en desuso.
A continuación dejo una tabla de PROS y Contras que he ido dilucidando a medida que iba desarrollando el tema de este post. Es susceptible a updates a medida que vaya apareciendo información sobre los nuevos productos, o se enciendan nuevas luces/inquietudes en mi cabeza. 

Solución
PROS
Contras
Formularios de lista
·         Completamente integrados con SP
·         Son realmente sencillos de construir
·         Se integran con Workflows
 
·         Imposible incluir lógica o formato condicional (salvo indicar qué campos son obligatorios)
·         Imposible incluir estructuras de repetición
·         Imposible modificar el diseño
·         Forzado a un único campo por fila
·         Es complejo disponer de columnas de datos de fuentes externas (no SharePoint)
Infopath
·         Se integra bastante bien con SP
·         Interface tipo Office.
·         Incorpora lógica / formato condicional.
·         Permite incluir estructuras de repetición (repeating tables, repeating zones)
·         Permite obtener datos externos con relativa facilidad.
·         El código HTML que genera es complejo.
·         Añadir código personalizado .NET es posible, pero complejo (lo desaconsejo).
·         El rendimiento es lento para casos de uso intensivos.
·         Tiene importantes limitaciones si la lista asociada no es una “form list”
·         Los controles que maneja no son tan intuitivos como los de SharePoint (peoplepicker, por ejemplo)
·         Ha sido condenado a “muerte”. Darán soporte pero no lo evolucionarán más
Encuestas de Excel
·         Interface muy intuitiva
·         No tiene dependencia de SharePoint
·         Facilidad de acceso a usuarios
·         Formularios listos en “5 minutos”
·         Los formularios resultantes son excesivamente sencillos. Solo permite construir tipos de campos básicos
·         Sin opciones de diseño del form.
·         El formato de presentación no se adapta a la naturaleza del campo (fechas o números los muestra como texto plano y no hay selector de fechas, por ejemplo).
·         No puede integrarse con Workflows u otras entidades de SharePoint.
·         Actualmente solo disponible en Excel Online y OneDrive.
·         Carencia de seguridad (puede acceder cualquier persona via URL)
Documentos estructurados
·         Integración nativa entre SharePoint (metadatos) y Word (documento y contenidos).
·         Todavía no disponible.
·         Hay poca información al respecto
·         Casuística de uso limitada (documentos tipo “papel” de alta fiabilidad, imprimibles, archivables).
Formularios Access
·         Access 2013 se integra perfectamente con SharePoint.
·         Ideal para gestionar tablas de datos relacionales.
·         Interface amigable. No requiere código.
·         Plantillas de tablas disponibles para acelerar la creación de nuevos forms.
·         Se pueden paquetizar las aplicaciones y subirlas a la Microsoft App Marketplace
·         Un Workflow no puede acceder a los campos del formulario.
·         No incorpora seguridad interna (vistas, campos…)
·         La App resultante pertenece a la BD y no se puede utilizar como frontend de una fuente de datos externa a ella (SharePoint List, por ejemplo).
FoSL
·         Se integrará perfectamente con SharePoint en futuras versiones.
·         Completamente integrado en el navegador. Sin invocar aplicaciones externas.
·         Estará desarrollado en HTML5, supuestamente un estándar web por muchos años.
·         Interface muy intuitiva Ribbon integrated.
·         Drag & Drop, se podrán mover y redimensionar libremente los campos del formulario.
·         Integración con fuentes de datos externas.
·         Se adaptará para dispositivos móviles.
·         No disponible actualmente.
·         Las primeras versiones serán muy limitadas en funcionalidad.
·         No está claro que proporcionen herramientas de migración para “antiguos” Infopaths.
·         Se intuyen limitaciones funcionales también a largo plazo (habrá que estar atentos al roadmap).
 
Desarrollo personalizado en Visual Studio y HTML5 / ASP.NET
·         Los únicos límites funcionales son los que impone el propio modelo y herramientas de desarrollo. Podemos construir cualquier formulario, con cualquier funcionalidad.
·         Desde HTML5 no debería ser compleja una posible futura migración a FoSL.
·         Requiere “picar código”, con todo lo que ello supone (especialización técnica requerida, entorno/licencias de desarrollo, posibles dificultades de migraciones a futuras versiones, dependencia del desarrollador…)
·          
Software de terceros
·         Suelen cubrir todas las funcionalidades que el usuario requiere para la construcción de los formularios.
·         Interfaces sencillas e intuitivas.
·         Incorpora lógica / formato condicional.
·         Permite incluir estructuras de repetición (repeating tables, repeating zones)
·         Permite obtener datos externos (Web Services)
·         Servicio de mantenimiento (actualizaciones periódicas y consultas incluido).
·         Adaptación a dispositivos móviles.
·         Coste de licenciamiento.
·         Coste de migración.

 Ahora sí os dejo, tras todo esta deserción sobre los formularios en SharePoint.
¡Salud!