Customising the Activity Views (and other such views) via Plugins

RetrieveMultiplePluginfeatureThe Requirement

I had a requirement to display a list of activities, both open and closed on the dashboard. Simple enough I hear you say. Well, it was until I needed to include a few more fields to make the user experience better. I wanted to categorise the activities, so as well as showing the type of activity (email,phone,letter,task), I wanted to give them a short description that would make a lengthy list of activities easily readable.

The Idea

Upon looking at the activities, such as email and phone call, I noticed they had a system default field called category, of which it was a single line of text. As it was present on all of the activities, I thought I would just use it. After much time spent updating my workflows to populate these category fields with the appropriate tags, I was ready to update the view.

The Problem

Bugger, it was then that I realised that the category field was unique to each activity, and not stored on the activity pointer (the entity that you would normally use to list all types of activities in one view). The activity pointer had the subject and description fields that are shared across other activities (plus a few more), but not the category field. And to top it off, the activity pointer entity is not customisable. So, at that point I started to think about using workflows or JavaScript to just simply prepend the tags I wanted to use to the beginning of the subject line, but it soon became apparent that it was not going to be suitable as there would be too much involved with making sure manual updates to activities didn’t spoil my tagging.

I began the “google”.

The Solution

Eventually, I happened upon a possible solution using plugins. Initially I was thinking of using a create or update plugin to change the subject field. Got too confusing, but, there was light at the end of the tunnel. I began experimenting with a plugin for the RetrieveMultiple command. This is what provides data for views within Dynamics, and even the activity pointer entity can have a RetrieveMultiple plugin to intercept the data it is about to send back to the web browser allowing you to tinker with the data returned.

To begin with, using the CRM Developer Toolkit for Visual Studio 2012, I browsed to the Activity Entity in the CRM Explorer window, right clicked and selected Create Plugin. Below are the selections I made to set up the plugin.

RetrieveMultiplePlugin

After that, I just added the code (at the bottom of this post) to intercept the returned EntityCollection’s subject field, and alter it in such a way so that it has the activities category and direction fields within.

The below line gets the EntityCollection that is about to be returned to the clients Grid View from the plugins OutputParameters collection.

EntityCollection entityCollection = (EntityCollection)localContext.PluginExecutionContext.OutputParameters["BusinessEntityCollection"];

I then loop through every entity, find the category from the appropriate activity entity (the activitypointer id is the same id that is stored within the email entity for example), and then modify the activitypointer’s subject attribute to include the category.

It really is that simple.

Interesting, this could be used in all kind of situations where you need to alter the displayed views (perhaps hiding fields based on security roles, or encrypting/decrypting passwords for viewing etc). One of the key uses though may be to retrieve data from other entities to include in a view that may not be possible by just using fetchxml.

Below is the Execute code to include in the plugin to achieve what I have described.

 protected void ExecutePostActivityRetrieveMultiple(LocalPluginContext localContext)
        {
            if (localContext == null)
            {
                throw new ArgumentNullException("localContext");
            }
            if (localContext.PluginExecutionContext.OutputParameters.Contains("BusinessEntityCollection"))
            {
                EntityCollection entityCollection = 
                    (EntityCollection)localContext.PluginExecutionContext.OutputParameters["BusinessEntityCollection"];
                if (true)       // This could be some form of user role check
                {
                    if (entityCollection.Entities.Count > 0)
                    {
                        Entity ActivityEntity = null;
                        foreach (Entity entity in entityCollection.Entities)
                        {
                            if (entity.Contains("activitytypecode"))
                            {
                                string type = entity.Attributes["activitytypecode"].ToString();
                                if (type != "")
                                {
                                    // These Activities have a direction field to indicate outgoing or incoming
                                    if (type == "email" || type == "letter" || type == "phonecall") 
                                        
                                        ActivityEntity = localContext.OrganizationService.Retrieve(
                                            type, entity.Id, new ColumnSet("category", "directioncode"));
                                    else
                                        ActivityEntity = localContext.OrganizationService.Retrieve(
                                            type, entity.Id, new ColumnSet("category"));
                                    if (ActivityEntity.Attributes.Contains("category"))
                                    {
                                        if (ActivityEntity.Attributes.Contains("directioncode"))
                                        {
                                            entity.Attributes["subject"] = 
                                                ActivityEntity.Attributes["category"].ToString().PadRight(30) + " - " +
                                                ((bool)ActivityEntity.Attributes["directioncode"] ? "Outgoing" : "Incoming")
                                                + " - " + entity.Attributes["subject"];
                                        }
                                        else
                                        {
                                            entity.Attributes["subject"] = 
                                                ActivityEntity.Attributes["category"].ToString().PadRight(30) + " - " + 
                                                entity.Attributes["subject"];
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

Leave a Reply