
One of the great things about the SalesLogix web client is how open it is for customizations. unlike in the SalesLogix LAN client the Activity main view page in the web client can be fully customized. I am going to walk through today how to add modify this screen. There are a few parts here but it is not too bad. For my purpose I am going to add a new tab called “Today’s Activities” that shows a similar list to the normal activity tab but with a slightly different layout. I will also show an easy way of hiding one of the standard tabs.
First off the activity list view, while it looks like a normal group list view in the SalesLogix web client is not a normal user customizable area. The screens look similar to the group lists because the same underlying web controls are used for both areas. The activity list view screen is a custom smart part called ActivityViewer.ascx found in the SmartParts/Activity folder. There is no code behind file, the code and markup are both contained in the ascx file.
If you look in the file you will see that 90% of the content is javascript code. The only markup is SalesLogix ListPanel and then a SalesLogix ScriptRecourceProvider. To modify the interface we need to start by adding some keys into the ScriptResourceProvider.
We will add one for the Tab Name, and then ones for the new column I will be adding to my tab’s grid. Here are my keys:
<SalesLogix:ResourceKeyName Key=”ActivityTabs_TodayOpen” />
<SalesLogix:ResourceKeyName Key=”ActivityColumn_OriginalDate” />
<SalesLogix:ResourceKeyName Key=”ActivityColumn_DateDiff” />
They can be added anywhere in the list of other keys as long as they are between the <key> tags.
Before we jump into code, lets also add these keys to the resource file. The resource file is located in the SmartParts/Activity/App_LocalResources folder and is called AcivityViewer.ascx.resx. We need to add resource definitions for the three keys we added above.
<data name=”ActivityTabs_TodayOpen” xml:space=”preserve”>
<value>Today’s Activities</value>
</data>
<data name=”ActivityColumn_OriginalDate” xml:space=”preserve”>
<value>Original Date</value>
</data>
<data name=”ActivityColumn_DateDiff” xml:space=”preserve”>
<value>Days Past Due</value>
</data>
OK so now lets jump back to the ascx file. The first function in the javasrcipt section needs to be modified for our new tab like so (new code shown in bold):
ScriptQueue.at.dom(function() {
Sage.SalesLogix.Controls.StandardMetaConverter.registerLocalizationStore(SR);
var list = window.<%= ActivityList.ClientID %>;
var defaultView = “<%= DefaultView %>”;
var defaultViewToId = {
“0”: “all_open”,
“1”: “literature”,
“2”: “event”,
“3”: “confirmation”,
“4”: “today_open”,
“actTabConfirm”: “confirmation”
};
This will add the definition of our tab.The name “today_open” is used in the next part of code to modify, where the tabItems array is initialized (again my code in bold). Also if you want to hide a tab you can do it easily like I have done by commenting out the one of the array members, in the this case “Events”:
var tabItems = [{
id: “all_open”,
title: SR.ActivityTabs_AllOpen,
connections: {
list: {
resource: “slxdata.ashx/slx/crm/-/activities/activity/all”,
parameters: { count: “true” }
},
summary: {
resource: “slxdata.ashx/slx/crm/-/activities/activity/all-summary”,
parameters: { count: “true” }
}
},
managers: { }
},
{
id: “literature”,
title: SR.ActivityTabs_Literature,
connections: {
list: {
resource: “slxdata.ashx/slx/crm/-/activities/literature/all”,
parameters: { count: “true” }
},
summary: false
},
managers: { }
},
//{
// id: “event”,
// title: SR.ActivityTabs_Events,
// connections: {
// list: {
// resource: “slxdata.ashx/slx/crm/-/activities/event/all”,
// parameters: { count: “true” }
// },
// summary: false
// },
// managers: { }
//},
{
id: “confirmation”,
title: SR.ActivityTabs_Confirmations,
connections: {
list: {
resource: “slxdata.ashx/slx/crm/-/activities/confirmation/all”,
parameters: { count: “true” }
},
summary: false
},
managers: { }
},
{
id: “today_open”,
title: SR.ActivityTabs_TodayOpen,
connections: {
list: {
resource: “slxdata.ashx/slx/crm/-/activities/activity/today”,
parameters: { count: “true” }
},
summary: false
},
managers: { }
}
];
Note my id matches what we added in the first block of code. Also note that the resource is utilizing the slxdata.ashx handler. This handler is not exposed for editing and is compiled in the Sage.SalesLogix.Web.UI.Activity.dll but we can use it with our new parameter called “today”.
If you do a search in the ascx file for getAccountLink(a) and look at that code and other code around it you will see how there are several functions that accept a parameter input and then return some value. These are used to display data in the actual grid and I want to add a function to calucalte the number of days between when the activity was first created and what the current start date is. Here is that function:
function getFXDateDiff(startDate, originalDate) {
if (originalDate==null || startDate==null )
return “0”;
else
{
var one_day=1000*60*60*24
var dateDiff = (startDate.getTime() – originalDate.getTime())/(one_day);
return Math.round(dateDiff);
}
}
Pretty simple. Just inputs two parameters and calculates the time difference.
That is all we need to do in the ascx file.
No people who have followed me so far are probably thinking that some things are conspicuously missing, like the layout definitions. Well this stuff is hidden away in a place you won’t likely find unless you know where to look. So here is the big secret. in the App_Data folder there is a ActivitiesViewConfiguration.xml file. open that up and we’ll finish our changes.
In this XML are the markups for each of the existing tabs. If you look at them you can see, for instance the All Open group has a group name attribute with field members, entities, conditions, etc. It also has a layout definition. Similarly there is the All Open Summary definition area. Lets add our own XML sections. After the close </group> tag for the All Open Summary section add the following:
<!– Todays Activity –>
<group name=”today” type=”Sage.Entity.Interfaces.IActivity, Sage.Entity.Interfaces”>
<query sparse=”true” count=”true” cacheable=”true”>
<fields>
<field name=”id” path=”a.ActivityId” key=”true”>a.id</field>
<field name=”activity_id”>a.id</field>
<field name=”type”>a.Type</field>
<field name=”typeDisplay”>”</field>
<field name=”attachmentCount”>a.AttachmentCount</field>
<field name=”attachment”>a.Attachment</field>
<field name=”recurring”>a.Recurring</field>
<field name=”alarm”>a.Alarm</field>
<field name=”startDate”>a.StartDate</field>
<field name=”timeless”>a.Timeless</field>
<field name=”description”>a.Description</field>
<field name=”contactName”>a.ContactName</field>
<field name=”accountName”>a.AccountName</field>
<field name=”duration”>a.Duration</field>
<field name=”contactId”>a.ContactId</field>
<field name=”leadId”>a.LeadId</field>
<field name=”leadName”>a.LeadName</field>
<field name=”accountId”>a.AccountId</field>
<field name=”ticketId”>a.TicketId</field>
<field name=”opportunityId”>a.OpportunityId</field>
<field name=”notes”>a.Notes</field>
<field name=”priority”>a.Priority</field>
<field name=”lastName”>au.UserInfo.LastName</field>
<field name=”firstName”>au.UserInfo.FirstName</field>
<field name=”recurIterations”>a.Recuriterations</field>
<field name=”recurPeriod”>a.Recurperiod</field>
<field name=”recurPeriodSpec”>a.Recurperiodspec</field>
<field name=”recurSkip”>a.Recurskip</field>
<field name=”userid”>a.UserId</field>
<field name=”ticketNumber”>a.TicketNumber</field>
<field name=”opportunityName”>a.OpportunityName</field>
<field name=”originalDate”>a.OriginalDate</field>
<field name=”dateDiff”>a.Duration</field>
<field name=”contactLead”>coalesce(a.ContactId, a.LeadId)</field>
</fields>
<entities>
<entity type=”Sage.Entity.Interfaces.IActivity, Sage.Entity.Interfaces” alias=”a”>Activity as a</entity>
<entity type=”Sage.Entity.Interfaces.IUser, Sage.Entity.Interfaces” alias=”au”>,User as au</entity>
</entities>
<conditions>
<!– join to User –>
<condition>a.UserId = au.id</condition>
<condition>
<![CDATA[
(a.StartDate>=convert(varchar(16),GetUTCDate()-1,101) and a.StartDate<convert(varchar(16),GetUTCDate()+1,101))
]]>
</condition>
<!– select only meeting, phone, todo and personal activities… –>
<condition>(a.Type in (262145, 262146, 262147, 262162))</condition>
<!– …that user has calendar access to with at least one attendee confirmed –>
<condition>
<![CDATA[
a.id in (
select
ua.ActivityId
from
UserActivity ua
where
ua.Status = ‘T’
and ua.UserId in (
select
uc.CalUser.Id
from
UserCalendar uc
, User u
where
uc.CalUser.Id = u.Id
and uc.OthersAccessToUserCal.Id = :userId
and u.Type not in (‘P’)
and ((u.Type not in (‘R’, ‘W’)) or (:userId = ‘ADMIN’))
)
)
]]>
</condition>
</conditions>
<ordering>
</ordering>
<grouping>
</grouping>
<parameters>
<parameter name=”userId” />
</parameters>
</query>
<layout>
<items>
<item dataIndex=”id” width=”55″ header=”ActivityColumn_Complete” sortable=”false”>
<![CDATA[ <a href=”{[getCompleteActivityLink(values)]}”>{[SR.ActivityColumn_Complete]}</a> ]]>
</item>
<item dataIndex=”typeDisplay” width=”110″ header=”ActivityColumn_ActivityType”>
<![CDATA[ <a href=”{[getEditActivityLink(values)]}” >
<img src=”{[getActivityTypeImageSmall(values.row.data.type)]}” />
{[values.row.data.typeDisplay]}</a> ]]>
</item>
<item dataIndex=”startDate” width=”110″ header=”ActivityColumn_DateTime”>
<![CDATA[ {[formatDateTime(values.value, values.row.data.timeless)]} ]]>
</item>
<item dataIndex=”originalDate” width=”100″ header=”ActivityColumn_OriginalDate”>
<![CDATA[ {[formatDateTime(values.value, values.row.data.timeless)]} ]]>
</item>
<item dataIndex=”dateDiff” width=”60″ header=”ActivityColumn_DateDiff”>
<![CDATA[ <div align=”right”>
{[getFXDateDiff(values.row.data.startDate, values.row.data.originalDate)]}</div> ]]>
</item>
<item dataIndex=”contactId” width=”55″ header=”ActivityColumn_Type”>
<![CDATA[ {[getContactType(values.row.data)]} ]]>
</item>
<item dataIndex=”contactName” width=”100″ header=”ActivityColumn_Name”>
<![CDATA[ {[getContactLink(values.row.data)]} ]]>
</item><item dataIndex=”description” width=”100″ header=”ActivityColumn_Regarding”>
<![CDATA[ {[values.value ? values.value : “”]} ]]>
</item>
<item dataIndex=”priority” width=”60″ header=”ActivityColumn_Priority”>
<![CDATA[ {[values.value ? values.value : “”]} ]]>
</item>
<item dataIndex=”lastName” width=”100″ header=”ActivityColumn_ScheduledFor”>
<![CDATA[ {[values.row.data.firstName ? [values.row.data.lastName,”, “, values.row.data.firstName].join(“”) : values.row.data.lastName]} ]]>
</item>
</items>
</layout>
</group>
A lot of stuff but pretty straight forward. A couple of thins to note:
- The group name is what we passed into the handler in the ascx js code.
- The fields are all of the fields available to be used. Not all are in the layout. You could remove some of these to possibly increase performance. I basically just copied the All Open fields but alos added the originalDate and dateDiff fields. Notice the dateDiff field is actually using the duration field. This is because later in the layout I am modifying the display value of this field using the getFXDateDiff javascript function from the ascx file.
- The last thing is the second condition in the conditions section where I restrict the activities to just those of a certain time span. The condition here is basically added as is to the SQL query that is run against the database. I had to use GetUTCDate instead of GetDate because the SalesLogix provider converts the GetDate function to SLXGetDate whenever it is used. SQL does not have a SLXGetDate so it pukes on that.
There you have it, hopefully pretty straight forward to follow. The key to figuring out how to modify this are is knowing about the XML file in the App_Code directory.
Hi Kris,
Is this also valid for ver 8.2? I am trying to add OpportunityName column to the All Open list view and would appreciate your guidance in the matter.
Thanks!!
I dont think this is still true for 8.2. That area has been converted to a dojo based screen. You need to build a custom js module that injects changes into the base screen