function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Alexandru IleanaAlexandru Ileana 

Service Cloud Console does not automatically refresh the View page on the Case object when overridden

Hello Everyone,

I have an issue with the service cloud console.

Normally when adding an attachment or adding a new comment, the Case tab will refresh, showing the modification as shown in the attachment named 'Standard and Expected behavior (no override).png'.
User-added image

Later we have overridden the standard View page of the Case object with a new custom visualforce page called 'TicketPageWrapper.page' as shown in the attachment 'Case View Overriden.png'.
User-added image

In order for the debugging process to be easier and to eliminate other possible causes from our side, I have eliminated all our custom scripts and left the page as simple as possible.

The code for the 'TicketPageWrapper.page' visualforce page is the following:
<apex:page standardController="Case" extensions="TicketPageWrapper">
    
    <apex:detail id="detailBlock" inlineEdit="true" relatedListHover="true" subject="{!Case.Id}" relatedList="true"/>
    
</apex:page>

After repeating the process the result looks as shown in the attachment named 'Faulted behavior (after override) - no refresh.png'. The automatic refresh does not occur.
User-added image

I am not sure if this can help but I have also attached the firebug console after the comment has been added in the overridden page ('Firebug output in overriden page.png').
User-added image

When refreshing the houl page, the comment appears and this is actually the problem. I would like to know why this happens and have the page refresh just like it used to before.

Other similar issues include the 'hideListButton' arrows not memorising the state after closing the ticket as shown in attachment 'hideListButton issue.png'
User-added image

as well as not being able to change the icon of this 'external page' which in fact is not external, using sforce.console.setTabIcon('/img/sprites/master.png');.
I was able to change the title however using: 'sforce.console.setTabTitle('Ticket #{!Case.CaseNumber}');' however.

The most important issue of all is the first one of course. The problem with the refresh.

I would like to know what can be done to bring back that functionality.

Any suggestion and information is welcome.

Thank you!

Best regards,
Alexandru.
Best Answer chosen by Alexandru Ileana
Alexandru IleanaAlexandru Ileana
Hello,

I have just written a huge answer and everything got deleted because I misclicked on a link.
I will just briefly say a few words now
  • You need to use Salesforce Console Integration Toolkit intensively
  • It has bugs... all refresh methids do not work when using overridden pages. It is probably because it uses iframes and these methods pass signals through callout functions.
  • These are callout functions. Once the call is done, you cannot retrieve values back. So multiple actions should be done like:
getEnclosingTabId( function(result){
    sforce.console.closeTab( result.Id );
});
  • My strategy:
    • I set a new title and icon for my overridden page.
    • I set up my subtabs (only works with subtabs made of custom visualforce pages or overriden pages) to redirect to the parent tab when they have to close with an added URL parameter (mustClosePage=yes)
Getting a URL parameter:
// Used for searching for the existance of a certain parameter
$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results==null){
       return null;
    }
    else{
       return results[1] || 0;
    }
}
  • A chain reaction occurs like this:
Subtab is trying to redirect to MAIN_TAB_URL?mustClosePage=yes -> main tab is the same as detail tab (first subtab of any tab with cloned info) and it identifies itself as that through some black magic -> since those two tabs are in sync, the same parameter ends up automatically in the main tab with more black magic -> I detect the parameter and try to close the tab.
  • I then check if the main tab has any children left (apart from itself) and if it does not, I do a tab reconstruction (kills itself and then recreates itself ... users can see it happen in real time and it is a bit annoying but it is the only way).
  • If it has at least one more child, I display a message explaining that if you simply refresh the main tab (page refresh while keeping the tab) the Highlits Panel will not update. If the user is not ok with that, he can do a hard refresh (I wrote a batch tab close and reconstruction of the main tab and all its children losin all comments not yet posted an other unfinished forms)
  • Code for closing the tab and other things like session expiration detection and a fix for this bug: accesing a console link with login.salesforce.com instead of INSATNCE.salesforce.com will add  "/ui/support/servicedesk/" to any new tab opened and breaks subtabs displaying an error (implementation not popsted). This code should run in the ready function in jQuery:
// If the code is running in the console application
if(sforce.console.isInConsole()) {
    
    // Get the enclosing tab Id (the current tab)
    sforce.console.getEnclosingTabId( function(getEnclosingTabIdResult) {
        
        // Check if this page must close (the page that loaded this one requires it to close 
        //-> ex: a comment is submitted and it cannot close itself... so it loads the ticket page in the same tab. That tab must not appear)
        if($.urlParam('mustClosePage') === 'yes') {
            // Close the current tab
            sforce.console.closeTab(getEnclosingTabIdResult.id);
        }
        // Check if this is a regular ticket page, without a close signal and if yes then set the close event
        else {
            // Check if a tab has been closed (it triggers for all close event for any tab as long as this page is active in the background - in any tab). We then start the page reload logic function.
            sforce.console.addEventListener(sforce.console.ConsoleEvent.CLOSE_TAB, function(closeTabResult) {
                executeFunctionIfSessionIsValid( checkIfTicketWasUpdatedAndRefreshIfNecessary(true) );
            });
        }
        
        sforce.console.getTabLink(sforce.console.TabLink.TAB_ONLY, getEnclosingTabIdResult.id, function(getTabLinkResult) {
            var currentTabURL = getTabLinkResult.tabLink;
            if(currentTabURL.substring(currentTabURL.length-4, currentTabURL.length) == "%2Fa")
                sforce.console.setTabLink();
            if (currentTabURL.indexOf("ui/support/servicedesk/ServiceDeskPage") != -1) {
                simpleDialog.html("<br/><p class='indentedParagraph'>The URL used to access Salesforce was not correct.</p>" +
                                  "<br/><p class='indentedParagraph'>The proper URL should be: \"{!SUBSTITUTE(SUBSTITUTE(LEFT($Api.Partner_Server_URL_210, FIND( '/services', $Api.Partner_Server_URL_260)), 'visual.force', 'salesforce'), 'c.', '')}\" but the current one for this ticket is: \"" + currentTabURL.substring(0, currentTabURL.indexOf("%2F")) + "\"</p>" +
                                  "<br/><p class='indentedParagraph'>This situation can occur if you have accessed this ticket through a URL of the form: \"<b>https://login.salesforce.com</b>\" or you have accessed a ticket from a mail using the URL of the old server (ex: eu1.salesforce.com instead of the current one).</p>" +
                                  "<br/><br/><p class='indentedParagraph'>In case you expereince problems using Salesforce as a result of this such as not being able to post comments, we recommend logging off and afterwards logging back in.</p>");
                simpleDialog.dialog({
                    draggable: false,
                    resizable: true,
                    width: 400,
                    height: "auto",
                    modal: true,
                    title: "Invalid URL when accesing page",
                    open: function(){
                        jQuery('.ui-widget-overlay').bind('click',function(){
                            simpleDialog.dialog('close');
                        })
                    },
                    buttons: {
                        "Close this message": function() {
                            $( this ).dialog( "close" );
                        }
                    }
                });
                simpleDialog.dialog( "open" );
                $("span[id*='status']").hide();
            }
        });
        
    });
    
}
  • Checking if the ticket was updating by comparing the initial last modified date with one obtained through javascript remoting on an action
This is the rest of the core related to console related actions. I did not explain everything, but hopefully it is enough to get a general image:
// Information: All console operations need to be 'one shot' meaning the next operation in the chain must be defined in the callback of the previous function

// A one shot function for setting the current tab's title and icon
function setTabTitleAndIcon() {
	
	if (sforce.console.isInConsole()) {
		
		// Set the primary tab title
		sforce.console.setTabTitle('{!Case.CaseNumber}');
		
		sforce.console.getEnclosingPrimaryTabId(function(primaryResult){
			// Set the primary tab icon
			sforce.console.setTabIcon('{!URLFOR($Resource.Icons, 'tickets_icon.png')}', primaryResult.id);
		});
		
		// Set the enclosing tab icon
		sforce.console.getEnclosingTabId(function(enclosingResult) {
			sforce.console.setTabIcon('{!URLFOR($Resource.Icons, 'tickets_icon.png')}', enclosingResult.id);
		});
		
	}
	
}




// A one shot function for opening the New Comment interface in a new subtab
function oneShotDisplayNewTabInterface( URL ) {
	// If the code is running in the console application then open the content in a subtab
	if(sforce.console.isInConsole())
		srcUp(URL);
	// If at the present moment the code is not running in a console application, simply navigate to the new comments visualforce page
	else
		window.location.href = URL;
}



// Check if the page represents a Service Cloud Console application and attempt to reopen the primary tab
function reloadContent() {
	
	// If the user is viewing the ticket in the Service Cloud Console
	if(sforce.console.isInConsole()) {
		
		// Information related to tabs
		var currentTabId,
			primaryTabId,
			primaryTabObjectId,
			focusedPrimaryTabId;
		
		
		// Get the enclosing tab Id (can be subtab or primary tab)
		sforce.console.getEnclosingTabId( function(getEnclosingTabIdResult) {
			currentTabId = getEnclosingTabIdResult.id;
			
			// Get the primary tab Id
			sforce.console.getEnclosingPrimaryTabId( function(getEnclosingPrimaryTabIdResult) {
				primaryTabId = getEnclosingPrimaryTabIdResult.id;
				
				// Get the primary tab object Id
				sforce.console.getEnclosingPrimaryTabObjectId( function(getEnclosingPrimaryTabObjectIdResult) {
					primaryTabObjectId = getEnclosingPrimaryTabObjectIdResult.id;
					
					// Get the focused primary tab Id
					sforce.console.getFocusedPrimaryTabId( function(getFocusedPrimaryTabIdResult) {
						focusedPrimaryTabId = getFocusedPrimaryTabIdResult.id;
						
						
						try {
							// Get all subtab Ids of the primaryTab
							sforce.console.getSubtabIds(primaryTabId, function(getSubtabIdsResult) {
								
								// If the operation was successfull
								if (getSubtabIdsResult.success) {
									
									// Check if there is only one subtab (Primary tab can be closed without losing data because only the detail tab remains)
									if (getSubtabIdsResult.ids.length == 1) {
										// Close and reopen the primary tab
										sforce.console.closeTab(primaryTabId);
										sforce.console.openPrimaryTab(null, "/{!Case.Id}", focusedPrimaryTabId === primaryTabId ? true : false, 
																	 '{!Case.CaseNumber}', function(openPrimaryTabResult) {
											if (!openPrimaryTabResult.success) {
												alert("Unable to refresh a primary tab for ticket {!Case.CaseNumber}. The tab was closed. Please reopen it manually. Error: " + openPrimaryTabResult);
											}
										});
									}
									// There is more than one subtab
									else {
										simpleDialog.html("<br/><p class='indentedParagraph'>The ticket has been modified since the page was opened.</p>" +
														  "<p class='indentedParagraph'>Because there are still subtabs open, the main tab will be automatically refreshed when all will be closed.</p>" +
														  
														  "<br/><br/><p class='indentedParagraph'>Explanation:</p><br/><h3>Page Refresh</h3><p class='indentedParagraph'>The information on this page will be refreshed but the highlights panel will be out of sync since it references the main tab as shown in the following image:</p>" +
														  "<img src=\"{!URLFOR($Resource.jQuery_CssFiles, 'img/for_explanations/Highlights_Panel_Desync.png')}\" style=\"width: 458.40px; height: 140px\"></img>" + 
														  
														  "<br/><br/><h3>Parent Tab Refresh</h3><p class='indentedParagraph'>The main tab will be closed and reopened. This will refresh the highlights panel, but you will lose any unsaved information from the subtabs as shown below:</p>" +
														  "<img src=\"{!URLFOR($Resource.jQuery_CssFiles, 'img/for_explanations/Highlights_Panel_Desync_fix.png')}\" style=\"width: 475.20px; height: 109.60px\"></img>");
										simpleDialog.dialog({
											draggable: false,
											resizable: true,
											width: 600,
											height: 600,
											maxHeight: 600,
											modal: true,
											title: 'The ticket has been modified',
											open: function(){
												jQuery('.ui-widget-overlay').bind('click',function(){
													simpleDialog.dialog('close');
												})
											},
											buttons: {
												"Page Refresh (Keep subtabs)": function() {
													$( this ).dialog( "close" );
													location.reload(true);
												},
												"Parent Tab Refresh (Close all subtabs)": function() {
													$( this ).dialog( "close" );
													if(confirm("This will close all the subtabs and you will lose the content contained within them. Are you sure?")) {
														
														sforce.console.closeTab(primaryTabId);
														sforce.console.openPrimaryTab(null, "/" + primaryTabObjectId, focusedPrimaryTabId === primaryTabId ? true : false, 
																					  sforce.connection.query("SELECT CaseNumber "
																											+ "FROM Case "
																											+ "WHERE Id = '" + primaryTabObjectId + "' "
																											+ "LIMIT 1").getArray("records")[0].CaseNumber,
																					  function(openPrimaryTabResult) {
																						  if (!openPrimaryTabResult.success) {
																							  alert("Unable to refresh a primary tab for ticket {!Case.CaseNumber}. The tab was closed. Please reopen it manually. Error: " + openPrimaryTabResult);
																						  }
														});
														
													}
												},
												"Do nothing": function() {
													$( this ).dialog( "close" );
												}
											}
										// End of dialog
										});
									// End of more than one subtab
									}
								
								// End of get all subtabs
								}
							
							// End get subtabIdsOfPrimaryTab
							});
							
						}
						catch(exc) {
							console.log("An error has occurred when attempting to reopen the primary tab. Exception: " + exc);
							location.reload(true);
						}
					
					// End get focusedPrimaryTab
					});
				// End get primaryTabObjectId
				});
			// End get primaryTabId
			});
		// End get currentTabId
		});
		
	}
	else {
		location.reload();
	}
	
}




// A function used to check for ticket updates
function checkIfTicketWasUpdatedAndRefreshIfNecessary( automaticRefresh, callbackFunction ) {
		
		try{
			Visualforce.remoting.Manager.invokeAction(
				'RemoteActionsClass.getLastUpdatedDateTimeForTicket', 
				'{!Case.Id}', 
				function(result, event) {
					
					// If errors have occurred display an error dialog
					if (!event.status) {
						showSimpleDialog('Data could not be obtained',
										 "<br/><p class='indentedParagraph'>Data could not be obtained from the server and the following error has occurred:</p>" +
										 "<br/><br/>" + event.message + 
										 "<br/><br/><p class='indentedParagraph'>Please refresh the current page.</p>");
					}
					
					
					// If no errors have occurred then proceed
					else {
						if (lastModifiedDateOfTicket == null)
							lastModifiedDateOfTicket = result;
						
						// Check if the new last modified date is newer than the old one and refresh the tab/page if necessary
						if (result != lastModifiedDateOfTicket) {
							
							// Display a refresh message letting the user know the ticket has been modified
							if(!automaticRefresh) {
								showSimpleDialog('The ticket has been modified',
												 "<br/><p class='indentedParagraph'>The ticket has been modified since the page was opened.</p>" +
												 "<br/><br/><p class='indentedParagraph'>Please refresh the current page in order to see the new changes and continue working on this ticket.</p>");
							}
							else
								reloadContent();
						
						}
						// If the ticket was not modified then execute the next operation given as parameter
						else {
							if (callbackFunction != null && typeof callbackFunction !== 'undefined')
								callbackFunction();
						}
					}
				},
				{escape: true}
			);
		}
		catch(remoteActionException) {
			if(typeof Visualforce === 'undefined' || remoteActionException === 'Remoting request invalid for your session.') {
				$("span[id*='status']").find("h1").html("The code for this page has been updated by an administrator.<br/>Please wait while the page reloads...<br/><br/>If this message is displayed for too long, then it is recommended to reload the page manually.");
				removeErrorAndStartSpinner();
				location.reload(true);
			}
			else {
				showSimpleDialog('Unable to retrieve the last update date of ticket',
								 "<br/><p class='indentedParagraph'>The current page was unable to retrieve the last update date of the current ticket.</p><br/>" +
								 "<p class='indentedParagraph'>The following exception has occurred:</p><br/>" + remoteActionException +
								 "<br/><br/><p class='indentedParagraph'>It is recommended to reload the current page.<br/>If the error still persists, please send the error information to an administrator.</p>");
			}
		}
}
Example of a custom comment object with a custom visualforce page that will be a subtab and redirect with the previously mentioned parameter in the URL via controller code:
// A one shot function for setting the current tab's title and icon
function setTabTitleAndIcon() {
    if (sforce.console.isInConsole()) {
        
        // Set the primary tab title
        sforce.console.setTabTitle("{!Custom_Ticket_Comments__c.Case__r.CaseNumber} - Comment");
        
        // Set the enclosing tab icon
        sforce.console.getEnclosingTabId(function(enclosingResult) {
            
            sforce.console.setTabIcon("{!URLFOR($Resource.Icons, 'tickets_icon.png')}", enclosingResult.id);
            // Check if a tab is closing
            sforce.console.addEventListener(sforce.console.ConsoleEvent.CLOSE_TAB, function(closeTabResult) {
                showSaveStatus();
            }, { tabId : enclosingResult.id });
            
        });
        
    }
    else
        document.title = "{!Custom_Ticket_Comments__c.Case__r.CaseNumber} - Comment";
}

Conclusions:
  • I have not used casefeed... but I imagine you are in a similar situation regardless of that tag
  • The refresh trick works only by using an overriden or custom subtab page sending a url parameter to the main tab
  • The main tab needs to do actions when it receives it: decide wether or not to do a simple refresh or a hard refresh by removing and readding everything possible only if you follow the order of operation in the function. Other orders can mess up your console and end up with tabs that do not appear, being unable to refresh the tab selector, tabs being closed with important information.
  • You cannot reliably set an on close event on the main tab to do this. When it closes it forgets what it was doing and you will have only partial subtabs open at the end. Or none. The on close event must be done in the child tab.
  • You should think about how many standard pages you want to have a refresh on the main tab and replace accordingly and readd the information with: apex:detail
  • You could search for changes every 10 seconds with a script in order to find changes in the last update date, but test intensively! This will allow you to refresh even on events such as modifying the ticket team, by selecting related objects and comparing the last modified date with the last modified date of the case
    SELECT LastModifiedDate FROM CaseTeamMember OrderBy LastModifiedDate DESC LIMIT 1
  • It is the only way to make this work as long as Salesforce does not realise that overridded pages are still part of the same domain (their explainaition was that the domains are firrerent between an external page and a standard one)
I hope this helps. Please let me know if you have further questions.

Best Regards,
Alexandru.

All Answers

SonamSonam (Salesforce Developers) 
This seems like its working as designed as explained in https://help.salesforce.com/apex/HTViewSolution?urlname=Why-do-I-need-to-refresh-the-console-to-see-updates-in-VF-page-in-service-console&language=en_US

You would need to use javacript to refresh the VF after save:https://help.salesforce.com/apex/HTViewSolution?urlname=Service-Cloud-Console-overridden-case-edit-tab-refreshes-incorrectly-1327107603001&language=en_US
 
Alexandru IleanaAlexandru Ileana

I have looked through these links and while I understand that having only custom visualforce pages and playing with the service console API would work just fine, in this case I am talking about the standard Case object page wrapped in a visualforce page. By doing so my original page becomes an external page and the ticket adding page as well as the new comment page appear in a subtab.

First of all I do not see how I cann add code in that subtab... It is a standard page I have no access through through code. I cannot set the focus to the parent Tab, I cannot identify the parent Tab, I cannot get the Id of the tab (where do I write that and how do I call it), I cannot write code inside the Case tab to refresh the page on focus because the tab remains in focus and most functions don't even work anyway in this case.

These commands are simply being ignored. If I hav code access in these standard pages I believe I would see something happen, but as it stands it does not work. The only thing I was able to do was change the onClick function in 'add attachment' to not use 'navigateToUrl' and instead open in a new primary tab. Not only does that tab not automatically get focus, but it is opened as an 'External page' as the title.

In short, the link provided is very general in it's explanation and only works for custom visualforce page <-> custom visualforce page relations. I would like to know if anyone has managed to make this possible and I would prefer a full visualforce page A code in the answer and full visualforce page B code if necessary.

Also I would like to know how to call a 'sforce.console....' type function from a standard subtab such as 'Ticket Comment Edit' (where I cannot write code). Perhaps that would help with the issue.

tggagnetggagne

Alexandru, did you every solve your problem?  We have a similar issue wrapping a case inside <support:casefeed />, and when the user adds an attachment the page doesn't refresh, and I don't see how I can get a notification an attachment is added so I can refresh it.

We tried creating a pushtopic and listening for it, but Attachment is an unsupported pushtopic. Groan.

Short of writing our own custom VF page for attachments, I'm unsure how to get around this.  I'm hoping you found an answer.

Alexandru IleanaAlexandru Ileana
Hello,

I have just written a huge answer and everything got deleted because I misclicked on a link.
I will just briefly say a few words now
  • You need to use Salesforce Console Integration Toolkit intensively
  • It has bugs... all refresh methids do not work when using overridden pages. It is probably because it uses iframes and these methods pass signals through callout functions.
  • These are callout functions. Once the call is done, you cannot retrieve values back. So multiple actions should be done like:
getEnclosingTabId( function(result){
    sforce.console.closeTab( result.Id );
});
  • My strategy:
    • I set a new title and icon for my overridden page.
    • I set up my subtabs (only works with subtabs made of custom visualforce pages or overriden pages) to redirect to the parent tab when they have to close with an added URL parameter (mustClosePage=yes)
Getting a URL parameter:
// Used for searching for the existance of a certain parameter
$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results==null){
       return null;
    }
    else{
       return results[1] || 0;
    }
}
  • A chain reaction occurs like this:
Subtab is trying to redirect to MAIN_TAB_URL?mustClosePage=yes -> main tab is the same as detail tab (first subtab of any tab with cloned info) and it identifies itself as that through some black magic -> since those two tabs are in sync, the same parameter ends up automatically in the main tab with more black magic -> I detect the parameter and try to close the tab.
  • I then check if the main tab has any children left (apart from itself) and if it does not, I do a tab reconstruction (kills itself and then recreates itself ... users can see it happen in real time and it is a bit annoying but it is the only way).
  • If it has at least one more child, I display a message explaining that if you simply refresh the main tab (page refresh while keeping the tab) the Highlits Panel will not update. If the user is not ok with that, he can do a hard refresh (I wrote a batch tab close and reconstruction of the main tab and all its children losin all comments not yet posted an other unfinished forms)
  • Code for closing the tab and other things like session expiration detection and a fix for this bug: accesing a console link with login.salesforce.com instead of INSATNCE.salesforce.com will add  "/ui/support/servicedesk/" to any new tab opened and breaks subtabs displaying an error (implementation not popsted). This code should run in the ready function in jQuery:
// If the code is running in the console application
if(sforce.console.isInConsole()) {
    
    // Get the enclosing tab Id (the current tab)
    sforce.console.getEnclosingTabId( function(getEnclosingTabIdResult) {
        
        // Check if this page must close (the page that loaded this one requires it to close 
        //-> ex: a comment is submitted and it cannot close itself... so it loads the ticket page in the same tab. That tab must not appear)
        if($.urlParam('mustClosePage') === 'yes') {
            // Close the current tab
            sforce.console.closeTab(getEnclosingTabIdResult.id);
        }
        // Check if this is a regular ticket page, without a close signal and if yes then set the close event
        else {
            // Check if a tab has been closed (it triggers for all close event for any tab as long as this page is active in the background - in any tab). We then start the page reload logic function.
            sforce.console.addEventListener(sforce.console.ConsoleEvent.CLOSE_TAB, function(closeTabResult) {
                executeFunctionIfSessionIsValid( checkIfTicketWasUpdatedAndRefreshIfNecessary(true) );
            });
        }
        
        sforce.console.getTabLink(sforce.console.TabLink.TAB_ONLY, getEnclosingTabIdResult.id, function(getTabLinkResult) {
            var currentTabURL = getTabLinkResult.tabLink;
            if(currentTabURL.substring(currentTabURL.length-4, currentTabURL.length) == "%2Fa")
                sforce.console.setTabLink();
            if (currentTabURL.indexOf("ui/support/servicedesk/ServiceDeskPage") != -1) {
                simpleDialog.html("<br/><p class='indentedParagraph'>The URL used to access Salesforce was not correct.</p>" +
                                  "<br/><p class='indentedParagraph'>The proper URL should be: \"{!SUBSTITUTE(SUBSTITUTE(LEFT($Api.Partner_Server_URL_210, FIND( '/services', $Api.Partner_Server_URL_260)), 'visual.force', 'salesforce'), 'c.', '')}\" but the current one for this ticket is: \"" + currentTabURL.substring(0, currentTabURL.indexOf("%2F")) + "\"</p>" +
                                  "<br/><p class='indentedParagraph'>This situation can occur if you have accessed this ticket through a URL of the form: \"<b>https://login.salesforce.com</b>\" or you have accessed a ticket from a mail using the URL of the old server (ex: eu1.salesforce.com instead of the current one).</p>" +
                                  "<br/><br/><p class='indentedParagraph'>In case you expereince problems using Salesforce as a result of this such as not being able to post comments, we recommend logging off and afterwards logging back in.</p>");
                simpleDialog.dialog({
                    draggable: false,
                    resizable: true,
                    width: 400,
                    height: "auto",
                    modal: true,
                    title: "Invalid URL when accesing page",
                    open: function(){
                        jQuery('.ui-widget-overlay').bind('click',function(){
                            simpleDialog.dialog('close');
                        })
                    },
                    buttons: {
                        "Close this message": function() {
                            $( this ).dialog( "close" );
                        }
                    }
                });
                simpleDialog.dialog( "open" );
                $("span[id*='status']").hide();
            }
        });
        
    });
    
}
  • Checking if the ticket was updating by comparing the initial last modified date with one obtained through javascript remoting on an action
This is the rest of the core related to console related actions. I did not explain everything, but hopefully it is enough to get a general image:
// Information: All console operations need to be 'one shot' meaning the next operation in the chain must be defined in the callback of the previous function

// A one shot function for setting the current tab's title and icon
function setTabTitleAndIcon() {
	
	if (sforce.console.isInConsole()) {
		
		// Set the primary tab title
		sforce.console.setTabTitle('{!Case.CaseNumber}');
		
		sforce.console.getEnclosingPrimaryTabId(function(primaryResult){
			// Set the primary tab icon
			sforce.console.setTabIcon('{!URLFOR($Resource.Icons, 'tickets_icon.png')}', primaryResult.id);
		});
		
		// Set the enclosing tab icon
		sforce.console.getEnclosingTabId(function(enclosingResult) {
			sforce.console.setTabIcon('{!URLFOR($Resource.Icons, 'tickets_icon.png')}', enclosingResult.id);
		});
		
	}
	
}




// A one shot function for opening the New Comment interface in a new subtab
function oneShotDisplayNewTabInterface( URL ) {
	// If the code is running in the console application then open the content in a subtab
	if(sforce.console.isInConsole())
		srcUp(URL);
	// If at the present moment the code is not running in a console application, simply navigate to the new comments visualforce page
	else
		window.location.href = URL;
}



// Check if the page represents a Service Cloud Console application and attempt to reopen the primary tab
function reloadContent() {
	
	// If the user is viewing the ticket in the Service Cloud Console
	if(sforce.console.isInConsole()) {
		
		// Information related to tabs
		var currentTabId,
			primaryTabId,
			primaryTabObjectId,
			focusedPrimaryTabId;
		
		
		// Get the enclosing tab Id (can be subtab or primary tab)
		sforce.console.getEnclosingTabId( function(getEnclosingTabIdResult) {
			currentTabId = getEnclosingTabIdResult.id;
			
			// Get the primary tab Id
			sforce.console.getEnclosingPrimaryTabId( function(getEnclosingPrimaryTabIdResult) {
				primaryTabId = getEnclosingPrimaryTabIdResult.id;
				
				// Get the primary tab object Id
				sforce.console.getEnclosingPrimaryTabObjectId( function(getEnclosingPrimaryTabObjectIdResult) {
					primaryTabObjectId = getEnclosingPrimaryTabObjectIdResult.id;
					
					// Get the focused primary tab Id
					sforce.console.getFocusedPrimaryTabId( function(getFocusedPrimaryTabIdResult) {
						focusedPrimaryTabId = getFocusedPrimaryTabIdResult.id;
						
						
						try {
							// Get all subtab Ids of the primaryTab
							sforce.console.getSubtabIds(primaryTabId, function(getSubtabIdsResult) {
								
								// If the operation was successfull
								if (getSubtabIdsResult.success) {
									
									// Check if there is only one subtab (Primary tab can be closed without losing data because only the detail tab remains)
									if (getSubtabIdsResult.ids.length == 1) {
										// Close and reopen the primary tab
										sforce.console.closeTab(primaryTabId);
										sforce.console.openPrimaryTab(null, "/{!Case.Id}", focusedPrimaryTabId === primaryTabId ? true : false, 
																	 '{!Case.CaseNumber}', function(openPrimaryTabResult) {
											if (!openPrimaryTabResult.success) {
												alert("Unable to refresh a primary tab for ticket {!Case.CaseNumber}. The tab was closed. Please reopen it manually. Error: " + openPrimaryTabResult);
											}
										});
									}
									// There is more than one subtab
									else {
										simpleDialog.html("<br/><p class='indentedParagraph'>The ticket has been modified since the page was opened.</p>" +
														  "<p class='indentedParagraph'>Because there are still subtabs open, the main tab will be automatically refreshed when all will be closed.</p>" +
														  
														  "<br/><br/><p class='indentedParagraph'>Explanation:</p><br/><h3>Page Refresh</h3><p class='indentedParagraph'>The information on this page will be refreshed but the highlights panel will be out of sync since it references the main tab as shown in the following image:</p>" +
														  "<img src=\"{!URLFOR($Resource.jQuery_CssFiles, 'img/for_explanations/Highlights_Panel_Desync.png')}\" style=\"width: 458.40px; height: 140px\"></img>" + 
														  
														  "<br/><br/><h3>Parent Tab Refresh</h3><p class='indentedParagraph'>The main tab will be closed and reopened. This will refresh the highlights panel, but you will lose any unsaved information from the subtabs as shown below:</p>" +
														  "<img src=\"{!URLFOR($Resource.jQuery_CssFiles, 'img/for_explanations/Highlights_Panel_Desync_fix.png')}\" style=\"width: 475.20px; height: 109.60px\"></img>");
										simpleDialog.dialog({
											draggable: false,
											resizable: true,
											width: 600,
											height: 600,
											maxHeight: 600,
											modal: true,
											title: 'The ticket has been modified',
											open: function(){
												jQuery('.ui-widget-overlay').bind('click',function(){
													simpleDialog.dialog('close');
												})
											},
											buttons: {
												"Page Refresh (Keep subtabs)": function() {
													$( this ).dialog( "close" );
													location.reload(true);
												},
												"Parent Tab Refresh (Close all subtabs)": function() {
													$( this ).dialog( "close" );
													if(confirm("This will close all the subtabs and you will lose the content contained within them. Are you sure?")) {
														
														sforce.console.closeTab(primaryTabId);
														sforce.console.openPrimaryTab(null, "/" + primaryTabObjectId, focusedPrimaryTabId === primaryTabId ? true : false, 
																					  sforce.connection.query("SELECT CaseNumber "
																											+ "FROM Case "
																											+ "WHERE Id = '" + primaryTabObjectId + "' "
																											+ "LIMIT 1").getArray("records")[0].CaseNumber,
																					  function(openPrimaryTabResult) {
																						  if (!openPrimaryTabResult.success) {
																							  alert("Unable to refresh a primary tab for ticket {!Case.CaseNumber}. The tab was closed. Please reopen it manually. Error: " + openPrimaryTabResult);
																						  }
														});
														
													}
												},
												"Do nothing": function() {
													$( this ).dialog( "close" );
												}
											}
										// End of dialog
										});
									// End of more than one subtab
									}
								
								// End of get all subtabs
								}
							
							// End get subtabIdsOfPrimaryTab
							});
							
						}
						catch(exc) {
							console.log("An error has occurred when attempting to reopen the primary tab. Exception: " + exc);
							location.reload(true);
						}
					
					// End get focusedPrimaryTab
					});
				// End get primaryTabObjectId
				});
			// End get primaryTabId
			});
		// End get currentTabId
		});
		
	}
	else {
		location.reload();
	}
	
}




// A function used to check for ticket updates
function checkIfTicketWasUpdatedAndRefreshIfNecessary( automaticRefresh, callbackFunction ) {
		
		try{
			Visualforce.remoting.Manager.invokeAction(
				'RemoteActionsClass.getLastUpdatedDateTimeForTicket', 
				'{!Case.Id}', 
				function(result, event) {
					
					// If errors have occurred display an error dialog
					if (!event.status) {
						showSimpleDialog('Data could not be obtained',
										 "<br/><p class='indentedParagraph'>Data could not be obtained from the server and the following error has occurred:</p>" +
										 "<br/><br/>" + event.message + 
										 "<br/><br/><p class='indentedParagraph'>Please refresh the current page.</p>");
					}
					
					
					// If no errors have occurred then proceed
					else {
						if (lastModifiedDateOfTicket == null)
							lastModifiedDateOfTicket = result;
						
						// Check if the new last modified date is newer than the old one and refresh the tab/page if necessary
						if (result != lastModifiedDateOfTicket) {
							
							// Display a refresh message letting the user know the ticket has been modified
							if(!automaticRefresh) {
								showSimpleDialog('The ticket has been modified',
												 "<br/><p class='indentedParagraph'>The ticket has been modified since the page was opened.</p>" +
												 "<br/><br/><p class='indentedParagraph'>Please refresh the current page in order to see the new changes and continue working on this ticket.</p>");
							}
							else
								reloadContent();
						
						}
						// If the ticket was not modified then execute the next operation given as parameter
						else {
							if (callbackFunction != null && typeof callbackFunction !== 'undefined')
								callbackFunction();
						}
					}
				},
				{escape: true}
			);
		}
		catch(remoteActionException) {
			if(typeof Visualforce === 'undefined' || remoteActionException === 'Remoting request invalid for your session.') {
				$("span[id*='status']").find("h1").html("The code for this page has been updated by an administrator.<br/>Please wait while the page reloads...<br/><br/>If this message is displayed for too long, then it is recommended to reload the page manually.");
				removeErrorAndStartSpinner();
				location.reload(true);
			}
			else {
				showSimpleDialog('Unable to retrieve the last update date of ticket',
								 "<br/><p class='indentedParagraph'>The current page was unable to retrieve the last update date of the current ticket.</p><br/>" +
								 "<p class='indentedParagraph'>The following exception has occurred:</p><br/>" + remoteActionException +
								 "<br/><br/><p class='indentedParagraph'>It is recommended to reload the current page.<br/>If the error still persists, please send the error information to an administrator.</p>");
			}
		}
}
Example of a custom comment object with a custom visualforce page that will be a subtab and redirect with the previously mentioned parameter in the URL via controller code:
// A one shot function for setting the current tab's title and icon
function setTabTitleAndIcon() {
    if (sforce.console.isInConsole()) {
        
        // Set the primary tab title
        sforce.console.setTabTitle("{!Custom_Ticket_Comments__c.Case__r.CaseNumber} - Comment");
        
        // Set the enclosing tab icon
        sforce.console.getEnclosingTabId(function(enclosingResult) {
            
            sforce.console.setTabIcon("{!URLFOR($Resource.Icons, 'tickets_icon.png')}", enclosingResult.id);
            // Check if a tab is closing
            sforce.console.addEventListener(sforce.console.ConsoleEvent.CLOSE_TAB, function(closeTabResult) {
                showSaveStatus();
            }, { tabId : enclosingResult.id });
            
        });
        
    }
    else
        document.title = "{!Custom_Ticket_Comments__c.Case__r.CaseNumber} - Comment";
}

Conclusions:
  • I have not used casefeed... but I imagine you are in a similar situation regardless of that tag
  • The refresh trick works only by using an overriden or custom subtab page sending a url parameter to the main tab
  • The main tab needs to do actions when it receives it: decide wether or not to do a simple refresh or a hard refresh by removing and readding everything possible only if you follow the order of operation in the function. Other orders can mess up your console and end up with tabs that do not appear, being unable to refresh the tab selector, tabs being closed with important information.
  • You cannot reliably set an on close event on the main tab to do this. When it closes it forgets what it was doing and you will have only partial subtabs open at the end. Or none. The on close event must be done in the child tab.
  • You should think about how many standard pages you want to have a refresh on the main tab and replace accordingly and readd the information with: apex:detail
  • You could search for changes every 10 seconds with a script in order to find changes in the last update date, but test intensively! This will allow you to refresh even on events such as modifying the ticket team, by selecting related objects and comparing the last modified date with the last modified date of the case
    SELECT LastModifiedDate FROM CaseTeamMember OrderBy LastModifiedDate DESC LIMIT 1
  • It is the only way to make this work as long as Salesforce does not realise that overridded pages are still part of the same domain (their explainaition was that the domains are firrerent between an external page and a standard one)
I hope this helps. Please let me know if you have further questions.

Best Regards,
Alexandru.
This was selected as the best answer
tggagnetggagne

Well, here's the easy answer (for us, at least).

We created a Case_History objects (our own) which is inserted into whenever a case-related object is created, deleted, or updated.  The first problem this solves is we can now track all field history without any limits, and report the changes on the Case, rather than having to navigate to the child objects (like tasks, attachments, comments, etc.)

The history is created by a simply three-line trigger on the child objects.

Now that every case-related insert/delete/change is recorded inside a single object, our Case VF page can now create a PushTopic and listen for changes to the object where our case is concerned.  When it receives the notification it simply re-renders <support:casefeed /> et voila.