SSD: el síndrome de la Sharepoint dependencia

Sharepoint me proporciona seguridad y me hace sentir más fuerte. Las 10 cosas que más me gustan de Sharepoint.

10 puntos para entender a Project Server 2010

Microsoft Project es quizá la herramienta de gestión de proyectos más conocida y utilizada por los líderes de proyectos...

Diseño Gráfico en SharePoint

Serie de artìculos que nos ayudan a incorporar diseño gráfico en las implementaciones de SharePoint...

Revista CompartiMOSS

Artículos publicados en la revista especializada en SharePoint: CompartiMOSS.

Contacto

Enviame un correo :-)

Mostrando entradas con la etiqueta Sharepoint. Mostrar todas las entradas
Mostrando entradas con la etiqueta Sharepoint. Mostrar todas las entradas

lunes, 27 de julio de 2015

Diseño Gráfico en SharePoint Foundation 2010 Parte 3.

Introducción

En artículos anteriores hicimos una introducción acerca de cómo incorporar en SharePoint 2010 los estilos creados por un diseñador gráfico. Nos basamos en algunas hipótesis como el uso de SharePoint Foundation, páginas maestras, hojas de estilo y modelo de objetos de cliente para JavaScript. Se recomienda leer la parte 1 y la parte 2 antes de continuar. También les recomiendo leer los ejemplos de CAML con Client Object Model, porque los utilizo para obtener datos de listas.

En esta tercera etapa, vamos a trabajar con dos casos puntuales:

· Botonera gráfica en reemplazo del Inicio Rápido

· Tablero de control con indicadores gráficos

Qué lo disfruten!

 

Botonera gráfica en reemplazo del Inicio Rápido

Lo primero que vamos a mostrar es cómo agregar una botonera con imágenes que reemplace al tradicional Inicio Rápido. Esta botonera se verá en todas las páginas. Para ello modificamos la página maestra y agregamos algunos estilos. El resultado final se ve en esta imagen:

image

Imagen 1 – Botonera gráfica en reemplazo de Inicio Rápido

 

El siguiente código muestra el agregado de la botonera en la página maestra

<div id="botonera_izquierda">

<div id="menu">

<ul id="nav">

<li><a href="/"><img src="/internal/nav_inicio_static.jpg" width="90" height="90"></a></li>

<li><a href="/Lists/Noticias"><img src="/internal/nav_noticias_static.jpg" width="90" height="90"></a></li>

<li><a href="/Lists/Personal"><img src="/internal/nav_nuestras_static.jpg" width="90" height="92"></a></li>

<li><a href="/Polticas"><img src="/internal/nav_politicas_static.jpg" width="90" height="91"></a></li>

<li><a href="/Formularios"><img src="/internal/nav_formularios_static.jpg" width="90" height="91"></a></li>

<li><a href="/Lists/Busquedas"><img src="/internal/nav_busquedas_static.jpg" width="90" height="91"></a></li>

<li><a href="/Lists/Menu"><img src="/internal/nav_menu_static.jpg" width="90" height="91"></a></li>

<li><a href="/Revistas/"><img src="/internal/nav_revista_static.jpg" width="90" height="91"></a></li>

<li><a href="/"><img src="/internal/nav_remises_static.jpg" width="90" height="91"></a></li>

<li><a href="/Capacitaciones"><img src="/internal/nav_capacitaciones_static.jpg" width="90" height="92"></a></li>

</ul>

</div>

</div>

 

El código debe ser agregado justo antes de esta línea:

<div id="s4-leftpanel-content">

 

Por otro lado, agregamos los siguientes estilos en nuestra hoja de estilos:

#s4-leftpanel { width: 95px !important;}

#s4-leftpanel-content { display: none; }

.s4-ca { margin-left: 95px; }

 

Un detalle más, queremos que los botones cambien a otra imagen en el momento en que pasamos el mouse por sobre ellos (hover), tal como se ve en la siguiente imagen:

image

Imagen 2 – Efecto Hover en la botonera

 

Con ese fin agregamos en la página maestra, el siguiente código jQuery:

<script type="text/javascript">

$('#nav a img').hover(

function() {

$(this).attr('src', $(this).attr('src').replace('static', 'over') );

},

function() {

$(this).attr('src', $(this).attr('src').replace('over', 'static') );

}

);

</script>

Tablero de control con indicadores gráficos

Cómo segundo ejemplo del día, vamos a agregar unos indicadores gráficos que se vean como los de la siguiente imagen:

image

Imagen 3 – Ejemplo de Tablero de Control

Estos indicadores serán generados a partir de información en listas usando CAML. En este caso usaremos una página de aplicación en C# con código de servidor por un tema de rendimiento, pero también podría ser JavaScript con Cliente Object Model.

Dentro de nuestra página ASP.Net llamaremos a una hoja de estilos además de crear el DIV “contenido”:

<asp:Content ID="Main" runat="server" contentplaceholderid="PlaceHolderMain" >

<div runat="server" ID="contenido" />

<link href="agea_telefonia_dashboard.css" type="text/css" rel="stylesheet" id="stylesheet" />

</asp:Content>

<asp:Content ID="PageTitle" runat="server" contentplaceholderid="PlaceHolderPageTitle" >

Panel de Control

</asp:Content>

<asp:Content ID="PageTitleInTitleArea" runat="server" contentplaceholderid="PlaceHolderPageTitleInTitleArea" >

Panel de Control

</asp:Content>

 

Leeremos la información vía CAML. No voy a mostrar en el código la lectura de información porque está muy relacionada con la lógica del negocio y no es más que lecturas típicas en CAML. Lo que si mostraré es cómo incorporar esos valores dentro de dos DIVs pensados para estructurar la información:

· DIV dash01 para el valor del indicador 1

· DIV dash01_detalle para el detalle del indicador 1

· Y así sucesivamente…

 

contenido.InnerHtml = "<div class='semaforos'>";

contenido.InnerHtml += "<div id='dash01' class='" + luz_indicador_1 + " dash'><p class='titulo'>CALENDARIO</p><p class='valor'>" + x_equipos_sin_linea + "</p><p class='leyenda'>Tiempos del Proyecto</p></div>";

contenido.InnerHtml += "<div id='dash02' class='" +

Continuar el armado de DIVs para el resto de los indicadores.

contenido.InnerHtml += "</div>";

contenido.InnerHtml += "<div id='dash01_detalle' class='detalle'>" + detalle_indicador_1 + "</div>";

contenido.InnerHtml += "<div id='dash02_detalle' class='detalle'>" +

Continuar el armado de DIVs de detalle para el resto de los indicadores.

 

Agregaremos además algo de código jQuery para que al presionar sobre un indicador, nos muestre la información de detalle. Para ello llamamos a los scripts correspondientes de ASPX:

Page.ClientScript.RegisterClientScriptInclude("dash_jquery", ResolveUrl("./jquery-1.8.2.min.js"));

Page.ClientScript.RegisterClientScriptInclude("dash_script", ResolveUrl("./dashboard.js"));

Page.ClientScript.RegisterStartupScript(this.GetType(), "dash_script", "asignar_botones();", true);

 

Y este es nuestro código jQuery “dashboard.js”:

function asignar_botones () {

$( document ).ready(function() {

$(".dash").click(function() {

var panel = "#" + $(this).attr('id') + "_detalle";

$(".detalle").css("display","none");

$(panel).slideDown( "slow" ).css("overflow","visible");

$(".dash").removeClass("dash_selected");

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

});

});

 

Por último nos queda incorporar nuestra hoja de estilo, cuidando que el diseño sea responsive y se adapte al ancho de la pantalla, como se ve en esta imagen (en una pantalla más angosta que la anterior):

image

Imagen 4 – Ejemplo de Tablero de Control con un ancho de pantalla más angosto

 

.dash { border: solid white 2px; }

.dash_selected { border: solid #333333 2px; }

.semaforos div {

float: left;

width: 22%;

margin: 3px;

padding: 15px 15px 10px 15px ;

}

.semaforos {

font-family: tahoma;

text-align: center;

cursor: pointer;

}

.verde { background-color: #8CC152; }

.rojo {background-color: #E9573F; }

.amarillo { background-color: #F6BB42;}

.gris{ background-color: #C8C8C; }

.valor {

color: #fff;

font-weight: 500;

font-size: 36px;

margin-top: 20px;

margin-bottom: 10px;

}

.titulo {

color: #fff;

font-size: 17px;

font-weight: 500;

}

.leyenda {

border-top: solid white 5px;

padding-top: 12px;

color: #fff;

font-size: 12px;

height: 65px;

}

.verde .leyenda { border-top-color: #76AD3E;}

.rojo .leyenda { border-top-color: #D1462C;}

.amarillo .leyenda { border-top-color: #E0A52C; }

.gris .leyenda { border-top-color: #737373; }

.detalle {

border-left: solid #E6E9ED 10px;

width: 95%;

height: 200px;

margin: 5px;

padding: 5px;

font-size: 11px;

font-family: tahoma;

clear: both;

display:none;

}

.detalle span {

font-size: 11px;

font-family: tahoma;

}

.detalle a {

padding: 5px;

font-size: 11px;

}

Conclusión

Esta fue la tercera entrega de esta colección de artículos dedicada a demostrar cómo se puede trabajar en SharePoint junto a un diseñador gráfico profesional. En mi opinión, esto es muy valorado por los clientes.

Les presento otra imagen del resultado final, ya vieron una en el artículo anterior. Espero como siempre que haya sido útil y cualquier duda me consultan. Saludos!

image

Imagen 5 – Diseño Gráfico aplicado a la página de inicio de SharePoint (caso 2)

 

Juan Pablo Pussacq Laborde

SharePoint MVP

Blog: http://surpoint.blogspot.com/

Facebook: http://facebook.com/surpointblog/

Twitter: http://twitter.com/jpussacq/

 

Publicado originalmente para revista COMPARTIMOSS

domingo, 9 de febrero de 2014

Ejemplos de CAML en Client Object Model (JavaScript)

Introducción

El modelo de objetos de cliente de SharePoint ha sido una gran incorporación en SharePoint 2010. Nos permite consultar información de listas, utilizando sólo un poco de código JavaScript. No se requiere desarrollo a nivel de servidor, ni permisos especiales en la granja de SharePoint.

Uno de los usos más comunes, que al menos yo le he dado, es consultar información de listas, para luego desplegarla  utilizando diferentes formas de presentación gráfica. Para ello, suelo utilizar consultas en lenguaje CAML. CAML tiene sus particularidades. En este breve artículo voy a presentar algunos ejemplos que me han resultado útiles.

En caso que nunca hayan utilizado Client Objetc Model, quizá sea conveniente que lean una introducción: http://surpoint.blogspot.com/2011/10/introduccion-al-modelo-de-objetos-de.html

 

Caso 1: empezando…

En el primer ejemplo, vamos a mostrar un caso completo. En los siguientes mostraremos sólo las variaciones. Imaginemos que necesitamos hacer una consulta simple, en donde veremos:

·         Cómo ordenar elementos

·         Cómo indicar qué columnas mostrar

·         Cómo indicar que queremos traer sólo una fila

 

function cargar_noticia_destacada() {

 contexto = new SP.ClientContext.get_current();

 var lista = contexto.get_site().get_rootWeb().get_lists().getByTitle('Noticias');

 var query = new SP.CamlQuery();

 var consulta =

  '<View>' +

  // Ordenada por fecha de cración (ID) descendente

  '<Query><OrderBy><FieldRef Name ="ID" Ascending="FALSE"/></OrderBy></Query>' +

  // Una sóla noticia

  '<RowLimit>1</RowLimit>' +

  '<ViewFields>' + 

  '<FieldRef Name="ID"/><FieldRef Name="Title"/><FieldRef Name="Resumen"/><FieldRef Name="Imagen_x0020_destacada"/>' +

  '</ViewFields>' +

  '</View>';

 query.set_viewXml(consulta);

 this.items = lista.getItems(query);

 contexto.load(items);

 contexto.executeQueryAsync(Function.createDelegate(this, this.cargaok_noticia_destacada), Function.createDelegate(this, this.cargamal));

}

 

En la siguiente función vemos  cómo procesar los ítems leídos. Esto por supuesto depende de nuestra página, pero lo muestro para que tengan un ejemplo de cómo se haría.

 

function cargaok_noticia_destacada(sender, args) {

var itemslista = this.items.getEnumerator();

while (itemslista.moveNext()) {

 var elitem = itemslista.get_current();

 var strHtmlImg  = elitem.get_item('Imagen_x0020_destacada').get_url();  

 var strHtmlTxt  ='<span class="h1">&gt; ' + elitem.get_item('Title') + '</span><br /><br />' + elitem.get_item('Resumen');

 var strHtmlBtn2 ='<a target="_self" href="javascript: AbrirVentanaModal(\'' + window.location.href.replace("/default.aspx","") + '/lists/Noticias/DispForm.aspx?ID=' + elitem.get_item('ID') + '&source=' + window.location.href + '\');"/>';  

 var strHtmlBtn1 ="<a href='" + window.location.href.replace("/default.aspx","") + '/lists/Noticias/' + "'/>";  

 }

// Imagen

$("#general_modulo1_img img").attr("src",strHtmlImg);

// Título y resumen

document.getElementById("general_modulo1_txt").innerHTML = strHtmlTxt  ;

// Noticia completa

$('#general_modulo1_btn td:nth-child(2) img').each(function() {

$(this).wrap(strHtmlBtn2);

       });

// Más noticias

$('#general_modulo1_btn td:nth-child(1) img').each(function() {

    $(this).wrap(strHtmlBtn1 );

});

$('#general_modulo1_btn td:nth-child(1) img').css("border","none");

}

 

Y finalmente nuestra rutina de error:

function cargamal(sender, args) {

alert('ERROR: ' + args.get_message() + '\n' + args.get_stackTrace());

}

 

Caso 2: agregando una condición

En este segundo ejemplo, vamos a ver cómo agregar una condición de igual sobre un campo de tipo texto:

'<Query><Where><Eq><FieldRef Name="Mostrar_x0020_en_x0020_p_x00e1_g"/><Value Type="Text">Si</Value></Eq></Where><OrderBy><FieldRef Name ="ID" Ascending="FALSE"/></OrderBy></Query>'

 

Caso 3: filtro por fecha actual

Supongamos ahora que queremos filtrar un campo fecha, comparándolo con la fecha del sistema. Veremos que necesitamos indicar el tipo de campo, e indicarle que no compare usando la hora:

'<Query><Where><Eq><FieldRef Name="Fecha"/><Value Type="DateTime" IncludeTimeValue="FALSE"><Today /></Value></Eq></Where></Query>'

 

Caso 4: filtrando entre fechas

Nuevamente compararemos con la fecha de sistema, pero esta vez, una comparación entre dos fechas:

'<Query><Where><And><Leq><FieldRef Name="Desde"/><Value Type="DateTime" IncludeTimeValue="FALSE"><Today/></Value></Leq><Geq><FieldRef Name="Hasta"/><Value Type="DateTime" IncludeTimeValue="FALSE"><Today/></Value></Geq></And></Where><OrderBy><FieldRef Name ="ID" Ascending="FALSE"/></OrderBy></Query>'

 

Caso 5: filtro por campo calculado

En el siguiente ejemplo, mostraremos cómo filtrar cuando nuestra columna es un campo calculado:

'<Query><Where><Eq><FieldRef Name="Apellido_x0020_y_x0020_nombre" /><Value Type="Computed">' + persona_seleccionada + '</Value></Eq></Where></Query>'

                              

Caso 6: filtro por campo de búsqueda

En este otro caso, vemos como filtrar en campos de búsqueda:

'<Query><Where><Eq><FieldRef Name="Usuario" LookupId="TRUE"/><Value Type="Lookup">' + usuario_conectado + '</Value></Eq></Where></Query>'

 

Caso 7: fecha ingresada por pantalla

Finalmente veremos un caso en donde necesitamos comparar contra una fecha ingresada por pantalla. El truco aquí es el formato de la fecha, el cual debemos formatear así:

var desde = ISODateString(Pdesde);

var hasta = ISODateString(Phasta);

 

La función utilizada es:

function ISODateString(d){

  function pad(n){return n<10 ? '0'+n : n}

  return d.getUTCFullYear()+'-'

      + pad(d.getUTCMonth()+1)+'-'

      + pad(d.getUTCDate())+'T'

      + pad(d.getUTCHours())+':'

      + pad(d.getUTCMinutes())+':'

      + pad(d.getUTCSeconds())+'Z'

}

Por último, el CAML para comparar las fechas ingresadas con las registradas en la lista:

'<Query><Where><And><Leq><FieldRef Name="Fecha"/><Value Type="DateTime" IncludeTimeValue="TRUE">' + hasta + '</Value></Leq><Geq><FieldRef Name="Fecha"/><Value Type="DateTime" IncludeTimeValue="FALSE">' + desde + '</Value></Geq></And></Where></Query>'

 

Conclusión

La utilización de Client Object Model de JavaScript nos brinda una forma muy sencilla de consultar información y mostrarla en una página de diferentes formas. En este breve artículo hemos mostrado algunas variantes del lenguaje de consulta CAML para entender cómo se aplican diferentes condiciones. Espero que les haya resultado útil. Hasta la próxima!

 

 

Juan Pablo Pussacq Laborde

SharePoint MVP

Blog: http://surpoint.blogspot.com/

Facebook: http://facebook.com/surpointblog/

Twitter: http://twitter.com/jpussacq/

 

Artículo publicado originalmente en: http://www.compartimoss.com/revistas/numero-17/ejemplos-caml-client-object-model-javascript

lunes, 3 de febrero de 2014

Modificar los enlaces de navegación en SharePoint 2007 vía programación

Supongamos que tenemos que modificar en forma masiva los enlaces de navegación de nuestro sitio. Por ejemplo, para corregir un error típico como puede ser la eliminación de direcciones absolutas.



Este es un requerimiento que puede resolverse con facilidad vía programación, a través de una página o una aplicación de consola. En este ejemplo, les muestro cómo hacerlo en una página ASPX para todos los sitios de la colección activa.

Espero les resulte útil !

<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Page Language="C#"
         Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" EnableViewStateMac="false" EnableViewState="true" MaintainScrollPositionOnPostback="true"%>

<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Navigation" %>

<script runat="server">

protected override void OnLoad(EventArgs e) {

string reemplazar = "http://misitio.com.ar";
string modificado;
string resultado = "<table><tr><td>It</td><td>Nombre</td><td>Url</td></tr>";

SPSite SI = SPContext.Current.Site;
SPWebCollection WEBS = SI.AllWebs;

foreach (SPWeb WE in WEBS) {

WE.AllowUnsafeUpdates = true;

resultado += "<tr><td><strong>" +  WE.Url + "</strong></td></tr>";

foreach (SPNavigationNode NODO in WE.Navigation.TopNavigationBar) {

resultado += "<tr><td>" +  NODO.Id + "</td><td>" +  NODO.Title + "</td><td>" +  NODO.Url + "</td></tr>";

if (NODO.Url.IndexOf(reemplazar) != -1) {
modificado = NODO.Url.Replace(reemplazar,"");

NODO.Url = modificado;
NODO.Update();

resultado += "<tr><td style='color:red;'>" +  modificado + "</td></tr>";
}

}

WE.Update();
WE.AllowUnsafeUpdates = false;

}


Response.ContentType = "text/plain";
Response.Write(resultado);


}

</script>

lunes, 1 de octubre de 2012

MVP SharePoint Server por otro año

Nuevamente tengo el honor de obtener el premio MVP por parte de Microsoft. Es realmente increíble, lo sigo tomando como uno de los hitos cumplidos más importantes de mi carrera. Muy contento y nuevamente a disfrutar!

image

Más información en: http://mvp.microsoft.com/es-ES/Paginas/default.aspx

“Hoy día, hay más de 4000 MVPs en todo el mundo. Ellos representan a más de 90 países, más de 40 lenguas, responden más de 10 millones de preguntas al año y han sido reconocidos en más de 90 tecnologías o productos Microsoft diferentes, reflejando la magnitud y el alcance de nuestros productos y las comunidades técnicas surgidas alrededor de estos.”

image

COMPARTIMOSS 13

Los invito a leer CompartiMOSS 13, la revista especializada en SharePoint en la que nuevamente tuve el honor de participar. Aquí les dejo los enlaces y el contenido. Que la disfruten!

  • imageEditorial
  • SharePoint por KO: KnockoutJS (Edin Kapic)
  • Colecciones de Sitios "Host-Named" en SharePoint 2013 (Juan Carlos González Martín)
  • La comunicación y el rol de la Intranet Corporativa (IC) (Juan Ibáñez)
  • 10 puntos para entender la Gestión estratégica del portfolio de proyectos en Project Server 2010 (Juan Pablo Pussacq Laborde)
  • MadPoint. Grupo de Usuarios de SharePoint de Madrid (Mario Cortés, Miguel Tabera)
  • Entrevista con Alberto Diaz Martin
  • Campo para Geolocalización en SharePoint 2013 (Luis Máñez)
  • Conexión de WebParts de Filtros y Cuadro de Mandos de PerformancePoint mediante programación (Adrián Díaz Cervera)
  • Novedades en Social Enterprise de SharePoint 2013 (Alberto Diaz Martin)
  • Explotando los Servicios de Excel desde aplicaciones externas mediante sus servicios web (José Andreu)
  • Novedades de Project Server 2013 (Arnau Roca, Reme Martínez, Marc Bàguena)
  • Portal en SharePoint para Ceibal (Leticia Jawad, Jorge Corral)
  • Compartir aplicaciones de servicio entre granjas SharePoint 2010 (Miguel Tabera Pacheco)

Enlace: http://www.gavd.net/servers/compartimoss/compartimoss_main.aspx

miércoles, 29 de agosto de 2012

¿Cómo cancelar todos los flujos de trabajo activos programáticamente?

La siguiente es una página de aplicación de SharePoint que permite cancelar todos los flujos de trabajo activos. Para ejecutarla, debe estar almacenada en la siguiente carpeta (o en una subcarpeta):

C:\Program Files\Common Files\microsoft shared\Web Server Extensions\12\TEMPLATE\LAYOUTS

Algunas consideraciones a tener en cuenta:

  • Esta página sólo cancela los flujos de trabajo de lista, pero no los de sitio (que existen desde SharePoint 2010)
  • Es posible que esta página tarde más de 6 minutos en ejecutar el código. En ese caso deberán modificar el web.config que se encuentra en la carpeta mencionada arriba, específicamente la línea <httpRuntime executionTimeout="360" />

A continuación el código. Espero les resulte útil!

<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>  
<%@ Register TagPrefix="spuc" Namespace="Microsoft.SharePoint.WebControls"
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" MasterPageFile="/_layouts/application.master"
         Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" %>

<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Workflow" %>
<%@ Import Namespace="System"%>
<%@ Import Namespace="System.Collections.Generic"%>
<%@ Import Namespace="System.Text"%>
<%@ Import Namespace="System.IO"%>

<script runat="server">
protected override void OnLoad(EventArgs e) {

FlujosTrabajo.Text = ""; // Salida por pantalla
int i = 0; // Cantidad de flujos activos
int s = 0; // Cantidad de sitios

Error.Text = "Ejecución exitosa";

try {
using (SPSite oSite = new SPSite("http://Surpoint"))
{
foreach (SPWeb oWeb in oSite.AllWebs)
// using (SPWeb oWeb = oSite.OpenWeb("/Blog/"))
{
oWeb.AllowUnsafeUpdates = true;
FlujosTrabajo.Text = FlujosTrabajo.Text + "Site: " + oWeb.Url + Environment.NewLine ;
s = s +1;
foreach (SPList list in oWeb.Lists)
{
// Verifico si la lista tiene flujos de trabajo
SPWorkflowAssociationCollection associationColl = list.WorkflowAssociations;
if (associationColl.Count >0)
{
FlujosTrabajo.Text = FlujosTrabajo.Text + " Lista: " + list.Title + " ("+ (list.Items.Count) +") [Workflows asociados: (" + associationColl.Count + ")]" + Environment.NewLine ;
for (int y=list.Items.Count-1; y>=0; y--)
{
SPListItem oItem = list.Items[y];
// Obtengo los flujos de trabajo activos para el ítem
SPWorkflowCollection wfs = oSite.WorkflowManager.GetItemActiveWorkflows(oItem);
if (wfs.Count >0)
{
FlujosTrabajo.Text = FlujosTrabajo.Text + " Ítem: " + oItem.ID + " [WF activos: (" + wfs.Count + ")]" + Environment.NewLine ;
for (int x=0; x<wfs.Count; x++)
{
SPWorkflow workflow = wfs[x];
FlujosTrabajo.Text = FlujosTrabajo.Text + " Workflow cancelado / ítem: " + workflow.ItemId;
i = i + 1;
// Cancelo el flujo de trabajo
SPWorkflowManager.CancelWorkflow(workflow);
FlujosTrabajo.Text = FlujosTrabajo.Text + " OK] " + Environment.NewLine ;
}
}
}
}
}
oWeb.AllowUnsafeUpdates = false;
oWeb.Dispose();
}
FlujosTrabajo.Text = FlujosTrabajo.Text + Environment.NewLine + "*** Total de workflows cancelados: " + i + " ***";
FlujosTrabajo.Text = FlujosTrabajo.Text + Environment.NewLine + "*** Total de sitios : " + s + " ***";
Error.Text = Error.Text + Environment.NewLine + "*** Total de workflows cancelados: " + i + " ***";
}
}
catch (Exception ex)
{
Error.Text = "*** Total de workflows cancelados: " + i + " ***";
Error.Text = Error.Text + Environment.NewLine + "Error: " + ex.Message;
}
}

</script>

<asp:Content ID="Main" runat="server" contentplaceholderid="PlaceHolderMain" >
<asp:TextBox ID="Error" runat="server" Visible="true" TextMode="MultiLine" Rows="3" Width="700px" />
<BR />
<asp:TextBox ID="FlujosTrabajo" runat="server" Visible="true" TextMode="MultiLine" Rows="20" Width="700px" />
</asp:Content>

miércoles, 22 de agosto de 2012

Soluciones para manejo de proyectos ágiles en SharePoint, Project y Project Server 2007, 2010 y 2013

Introducción

El propósito de este artículo es describir qué opciones existen para implementar metodologías ágiles en SharePoint, Project y Project Server. Existen soluciones distintas para cada versión (2007, 2010 o 2013) y también varían de acuerdo al producto. La idea es recorrer las distintas versiones para que, independientemente de la versión actual, también se pueda observar hacia dónde evoluciona el producto.

En líneas generales se observan dos grandes ramas de soluciones:

· Las que incorporan gráficos como el Burn Down en Microsof Project

· Las que incorporan el Task Board en SharePoint

Otra característica es que no encontramos soluciones para Project Server.

La siguiente tabla es un resumen de las soluciones incluidas en este artículo:

Solución

Software

SCRUM Template for SharePoint 2007 and 2010 http://scrum.codeplex.com/

SharePoint 2007 / 2010

21 Scrum http://www.21scrum.com/

SharePoint 2010

Project 2007 – Burndown Report http://archive.msdn.microsoft.com/P2010Scrum

Project 2007 / 2010

Project 2010 Scrum Solution starter http://archive.msdn.microsoft.com/P2010Scrum

Project 2010

Project 2013 – Burndown Report http://office.microsoft.com/en-us/project-help/create-a-burndown-report-HA102843516.aspx

Project 2013

 

clip_image002SCRUM Template for SharePoint 2007 and 2010

Se trata de una solución actualmente en desarrollo disponible en CodePlex que soporta como principales características:

· Sprint Backlog

· Scrum Burndown Chart

· Scrum Task Board

La siguiente imagen es un ejemplo del Scrum Task Board, que nos permite definir nuestras propias columnas, muestra el avance de las tareas, el estado y el avatar.

clip_image004

Esta solución tiene algunas opiniones negativas en el sitio. De todas maneras, es una alternativa a probar, e incluso una buena fuente de ideas. Además es de código abierto bajo licencia EPL.

Disponible para SharePoint 2007 y 2010

 

21 Scrum

Aparece como una de las opciones más recomendadas. Incluso hay una recomendación en un blog de Microsoft. No es una solución gratuita y sólo está disponible para SharePoint 2010. Sus opciones de licenciamiento son:

· Para una colección de sitios

· 5 colecciones

· Granja

clip_image006

 

Microsoft Project 2007 Burn Down Report

Desde el blog de Microsoft nos brindan un ejemplo de cómo construir un Burn Down Report en Project 2007 utilizando la característica de Reportes Visuales. Un ejemplo de gráfico a obtener es:

clip_image007

El resumen de pasos a seguir es:

1. Elegir la opción de Reportes Visuales

2. Elegir “Assignment Usage” de los reportes de Excel

3. Agregar cómo fila las semanas

4. Agregar como columnas trabajo acumulado, trabajo real y trabajo planificado

5. Crear las columnas para calcular el trabajo pendiente real y planificado.

6. Armar el gráfico

Si bien es una alternativa válida, requiere algo de trabajo manual y requiere que el líder maneje los valores reales de Project, algo que a veces no es tan común.

 

Microsoft Project 2010 Scrum Solution starter

Se trata de una solución disponible desde Microsoft sólo para Project 2010. Sus principales características son:

· Product backlog

· Scrum backlog

· Burndown charts

La instalación del producto nos genera una opción de creación de proyecto con Scrum:

clip_image008

Esto nos creara una solapa para Scrum dentro de la ribbon:

clip_image010

En la siguiente pantalla se ve un ejemplo de Sprint Burndown

clip_image012

 

Project 2013 – Burndown Report

Project 2013 maneja en forma nativa los “burndown reports”, al menos en lo que se puede ver en el preview. Para crear uno, se puede acceder en la ribbon desde Report > Dashboard > Burndown:

clip_image013

Podemos obtener un gráfico cómo el siguiente:

clip_image014

En el enlace se explican algunas ideas de cómo utilizar Project para obtener este tipo de gráficos.

 

Conclusión

clip_image016Recordando que el propósito de este artículo era buscar soluciones ágiles para Project Server, la primera conclusión es que no existen. Si dividimos un poco más ese objetivo, se encuentran algunas alternativas para Project y otras para SharePoint.

A priori, no aparece una alternativa que sobresalga del resto como para “recomendarla”, pero si aparecen ideas que pueden ser tomadas como base para una implementación de metodologías ágiles en una instalación de Project Server.

Teniendo en cuenta que en una instalación de Project Server, Project es una herramienta “obligada”, parece tener bastante sentido intentar sacar gráficos como el Burn Down desde esta herramienta, así como también gestionar los Sprints y el Product Backlog. Sin embargo, al tratarse de Project Server, no deberíamos descartar la opción de Reporting Services para generar los gráficos.

De todas maneras, es importante evaluar qué tan cómoda resulta esta herramienta para un equipo que trabaja con metodologías ágiles. Y hay que tener en cuenta que sólo podría ser utilizada para el rol de Scrum Master.

La otra parte de la conclusión es que parece ser interesante intentar armar algún tipo de pizarra en SharePoint. Y aquí hay algunas opciones para tomar de base, mientras que las necesidades más puntuales se podrían implementar con algo de desarrollo a medida (o incluso con algún tipo de herramienta no Microsoft, pero que pueda ser integrada dentro de SharePoint).

Un posible de resumen de pasos a seguir para hacer convivir metodologías ágiles dentro de una organización que implemente Project Server sería:

1. Entender la implementación de SCRUM (u otra metodología ágil) dentro de la organización.

2. Definir qué artefactos se implementarán en Project y cuáles en SharePoint.

3. Realizar las parametrizaciones y desarrollos necesarios, que a priori incluirían:

  · Una plantilla de Project

  · Una plantilla de Sitio de Proyecto

  · Reportes en Reporting Services que soporten Scrum

 

¿Y ustedes que experiencia han tenido con metodologías ágiles en Project Server y SharePoint? Los invito a opinar. Hasta la próxima!