Skip to main content

We use a third party workflow solution as part of our core client offering. One of our clients recently asked that they be able to see the previous assignee on a task that has been delegated or escalated to them. The click path (4 clicks) from the item to the correct workflow history where the information is displayed was a little too cumbersome.


Our third party workflow solution uses a custom workflow task page which is not editable so adding a web part was out of the question. So the only viable option in this case was to use a JavaScript only solution embedded in the master page. This solution allows me to deploy the solution on a client by client basis and make client specific customizations a relatively trivial task.

 

The solution uses the Nintex Web Service method GetWorkflowHistoryForListItem and parses the return data to display only the delegation information, puts it into a table (ugly stuff here) and appends it to an element at the bottom of the page that is a core piece of the providers solution.


The code consists of some variables and 4 function calls. First here are the variables I use:

 // name of the list passed to the web service var wsList = ""; // the item id parsed from the workflowLink var itemID="";  // the list that will be passed to the Nintex Web Service call. var listName="";  // get the Task ID var id = getUrlParameter('ID');  // Get the list guid  var list = getUrlParameter('List');‍‍‍‍‍‍‍‍‍‍


getUrlParameter is just a utility script I grabbed somewhere that does what the name suggests. I use it to get the taskID and the list guid from the querystring of the task page where I want the history displayed.

  function getUrlParameter(name) {   name = name.replace(/ \a]/, '\\m').replace(/\\]]/, '\\]');   var regex = new RegExp('r\\?&]' + name + '=(\^&#]*)');   var results = regex.exec(location.search);   return results === null ? '' : decodeURIComponent(resultsd1].replace(/\+/g, ' '));  };‍‍‍‍‍‍


Once I've got the basic info I need for my function call (id and list) I'm ready to call getListInfo. This gets the item ID of the list that the workflow is running against by grabbing the Workflowlink URL and pulling off the item ID. It also pulls the name of the list, since in my solution there could be multiple lists using the same custom task form and I'll need to pass that to the Nintex web service.

function getListInfo(list) {    var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists(guid'" + list + "')/items("+id+")";    var requestHeaders = { "accept": "application/json;odata=verbose" };    $.ajax({        url: requestUri,        contentType: "application/json;odata=verbose",        headers: requestHeaders,        success: onSuccess,        error: onError    });        function onSuccess(data, request) {           RelatedContent = data.d.WorkflowLink.Url;           var Start = RelatedContent.indexOf('Lists/')+6;           var End = RelatedContent.indexOf('/DispForm');           wsList = RelatedContent.slice(Start, End);           itemID = RelatedContent.slice(RelatedContent.lastIndexOf("=")+1)           // call the web service to get the hitory           getWorkflowHistory(itemID, wsList)        }         function onError(error) {//handle error if you need to.}}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

The getWorkflowHistory function is what calls the GetWorkflowHistoryForListItem web service. It's soap call and it returns XML. If successful I call processResults where things get really ugly and I apologize in advance for that. 

function getWorkflowHistory(itemID, wsList){          wsUrl =  _spPageContextInfo.webAbsoluteUrl + "/_vti_bin/NintexWorkflow/Workflow.asmx";          var soapEnv = '<?xml version="1.0" encoding="utf-8"?>'          + '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://nintex.com">'          + '  <soap:Header>'          + '  </soap:Header>'          + '  <soap:Body>'          + '    <m:GetWorkflowHistoryForListItem>'          + '      <m:itemId>'+itemID+'</m:itemId>'          + '      <m:listName>'+wsList+'</m:listName>'          + '      <m:stateFilter>Running</m:stateFilter>'          + '      <m:workflowNameFilter></m:workflowNameFilter>'          + '    </m:GetWorkflowHistoryForListItem>'          + '  </soap:Body>'          + '</soap:Envelope>';                         $.ajax({        url: wsUrl,        type: "POST",        dataType: "xml",        data: soapEnv,        complete: processResult     ,        contentType: "text/xml; charset=\"utf-8\""    });     }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

In processResults I parse the response xml and format the specific bits that satisfy my requirements, saving them to a variable called dataX. If there's bits in there then I append the table to a div element that is on the task page in our solution.

function processResult(xData, status) {  //alert((xData.responseText));  var dataX = "";  var CompletedDateTime ="";  var escalatesub = "No response to approval request";  var escalatesub2 = " has not responded with approval";  var dataHeader = '<tr><td colspan="5" valign="top">Delegation / Escalation History</td></tr>'+                    '<tr><td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede;">Previous Assignee</td>' +                    '<td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede;">Assigned Time</td>'+                                       '<td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede;">Outcome</td>'+                    '<td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede;">Comments</td></tr>';  if($(xData.responseText).find('GetWorkflowHistoryForListItemResult').text().length != 0){       $(xData.responseText).find('GetWorkflowHistoryForListItemResult').find('WorkflowLog').find('HumanTasks').find('HumanTaskLogInfo').each(function() {     var outcome = $(this).find('Outcome').text();     if(outcome == 'Delegated'){     var enteredDate = $(this).find('UserActionDateShort').text(); //assigned date     var enteredTime = $(this).find('UserActionTimeShort').text(); //assigned time     var user = $(this).find('DisplayName').text(); // The user assigned / performed the task action.     var userComments = $(this).find('UserComments').text().replace('i:0#.w|','');        switch(outcome){                         case 'Delegated':       if(userComments.indexOf(escalatesub) > 0){outcome = "Auto-Escalated";}       if(userComments.indexOf(escalatesub2) > 0){outcome = "Auto-Escalated";}       break;     case 'Pending':      case 'Not Required':        case 'Completed Task':        case 'Continue':            break;        default:        }     dataX += '<tr><td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff;">' + user +'</td>'+     '<td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff;">' +enteredDate + ' ' + enteredTime +'</td>'+     '<td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff;">' + outcome +'</td>'+     '<td style="border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff; word-wrap:break-word;">' + userComments + '</td></tr>';   }     });}if(dataX.length > 0){ dataX += "<table class='WFHist' style='font-family: verdana,arial,sans-serif; font-size:11px; color:#333333; border-width: 1px; border-color: #666666; border-collapse: collapse; table-layout:fixed;'>" + dataHeader + dataX + "</table>";if(document.getElementById('ctl00_PlaceHolderMain_invoiceFieldPanel') != null) {     $('#ctl00_PlaceHolderMain_invoiceFieldPanel').append("<tr><td nowrap='true' valign='top'> </td><td>" +  dataX + "</td></tr>");}}}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

 

 

Finally, to kick it off I use the following bit.

if(list.length > 0){getListInfo(list);}

@vacoder

Nice to see a different way to approach this, which was covered earlier in another blog post link below, though please share an output image of your solution, to understand how it differs.

https://community.nintex.com/news-18/get-task-history-and-display-on-your-form-30731

 


We aren’t using forms. Here’s how it looks :

 


Thanks for mentioning this criterion, make much more sense now.


Reply