Sitecore 7: Workflow with more than a Comment

Posted 10/28/2013 by asura

We recently got a requirement where the client wanted to store more than just a comment when a workflow item is approved or denied. So we built a proof of concept.

Truthfully, if the client were to implement this, I would want to use item buckets to store the values (based on a template) and store the item’s GUID in place of the comments (GUID:{81FEEE94-5A2F-4629-A791-4F25E69C75B1}). This would need customization of the whole Work Box. We will reassess this when the client gives the go ahead.

As per the proof of concept, I ended up just storing the delimited string in the comments. It does not look that bad since it only has 3 fields but if we were to store multiple fields of different data types it would get messy.

Comments Sample

A standard workflow item approval/rejection will prompt you with the box similar to what is shown below:

Standard Workflow Comment

I modified it to the one shown below:

Customized Workflow Comment

The fields you see in the dialog are for DEMO purposes only. The actual fields used in the proof of concept were from the client’s standard workflow process and had to meet their guidelines.

Step 1 – Override

To implement this we need to override the functionality in Workbox.xml. To do this, create the following folders under WebsitesitecoreshellOverride folder:

  • Applications

Copy Workbox.xml from WebsitesitecoreshellApplicationsWorkbox

Step 2 – Code Behind

Use a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for Sitecore.Shell.Applications.WorkboxForm.

Add a WorkboxForm class in your BL or Sitecore Extensions project to mirror the Sitecore.Shell.Applications.Workbox.WorkboxForm class.

Step 3 – CodeBeside

Modify the Workbox.xml file in the override folder to replace the value in the CodeBeside tag.

Step 4 – Create Custom Dialog Layout

We will create a XAML interface using an XML Layout.

  1. Switch to Core
  2. Open Dev Center
  3. Create new file of type CML Layout 
  4. Name the file Workflow Info
  5. Select the LayoutsDialogs location and click next
  6. Select file location as you choose (Layouts) and click next
  7. Click finish

Step 4 – XAML

Once the Layout file is created use the following code to define the interface elements.

Step 5 – Dialog CodeBeside

Create a new class in your BL or SitecoreExtensions project called WorkflowInfo. We are going to define two events as shown below:

As you can see in the OnOK event, we format the values from the interface elements and pass it back to the caller.

Step 6 – Back to Core

While in Core db via Sitecore admin console, navigate tot sitecorecontentApplicationsDialogs and create an item of type Folder, name it Workflow Info.

Set the layout on this item to LayoutsDialogsWorkflow Info

Core DB

Step 7 – Magic

In the WorkboxForm class in your code, locate the Comment method. Comment out the Enter a comment line as shown highlighted in the code below and replace it with the line 15 – 19.

/// /// The arguments. /// public void Comment(ClientPipelineArgs args) { Assert.ArgumentNotNull(args, “args”); if (!args.IsPostBack) { //Context.ClientPage.ClientResponse.Input(“Enter a comment:”, string.Empty); //args.WaitForPostBack(); //get core db var db = Sitecore.Data.Database.GetDatabase(“core”); //get the dialog item we created under applications var item = db.GetItem(Sitecored7.Utils.Constants.ItemsID.WorkFlowInfoDialog); //get dialog link var url = new UrlString(LinkManager.GetItemUrl(item)); //display Modal and wait for the post back Sitecore.Context.ClientPage.ClientResponse.ShowModalDialog(url.ToString(), true); args.WaitForPostBack(); return; } if (args.Result.Length > 2000) { Context.ClientPage.ClientResponse.ShowError(new Exception(string.Format(“The comment is too long.nnYou have entered {0} characters.nA comment cannot contain more than 2000 characters.”, args.Result.Length))); Context.ClientPage.ClientResponse.Input(“Enter a comment:”, string.Empty); args.WaitForPostBack(); return; } if (args.Result != null && args.Result != “null” && args.Result != “undefined”) { IWorkflowProvider workflowProvider = Context.ContentDatabase.WorkflowProvider; if (workflowProvider != null) { IWorkflow workflow = workflowProvider.GetWorkflow(Context.ClientPage.ServerProperties[“workflowid”] as string); if (workflow != null) { ItemRecords items = Context.ContentDatabase.Items; object item = Context.ClientPage.ServerProperties[“id”]; object empty = item; if (item == null) { empty = string.Empty; } Item item1 = items[empty.ToString(), Language.Parse(Context.ClientPage.ServerProperties[“language”] as string), Sitecore.Data.Version.Parse(Context.ClientPage.ServerProperties[“version”] as string)]; if (item1 != null) { try { workflow.Execute(Context.ClientPage.ServerProperties[“command”] as string, item1, args.Result, true, new object[0]); } catch (WorkflowStateMissingException workflowStateMissingException) { SheerResponse.Alert(“One or more items could not be processed because their workflow state does not specify the next step.”, new string[0]); } UrlString urlString = new UrlString(WebUtil.GetRawUrl()); urlString[“reload”] = “1”; Context.ClientPage.ClientResponse.SetLocation(urlString.ToString()); } } } } }

And that is it. If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.