Introduction
In this blog post, I am going to explain how to set up global actions and object-specific actions by using visualforce page.The global action which we are going to see in this blog is to send the message to slack channel and object specific action is to take the case ownership from the assigned queues.
Global Actions:-
As we are going to going to post the message to slack by using the global action, go and create a Slack app and get the slack token. Please refer this link
visualforce page is here below
<apex:page controller="GlobalSlackActions" lightningStylesheets="true" sidebar="false" showQuickActionVfHeader="false" docType="html-5.0">
<apex:slds />
/canvas/sdk/js/publisher.js
<div class="slds-scope">
<apex:form >
<apex:actionFunction action="{!postMessagetoSlack}" name="postSlackMessage" rerender="out"
oncomplete="refreshFeed();"/>
<apex:outputPanel id="out">
<div class="slds-form--compound slds-m-top--xxx-small">
<div class="slds-form-element">
<div class="slds-form-element__row slds-align_absolute-center">
<label class="slds-form-element__label" for="sample1">#Slack Channel</label>
<div class="slds-form-element__control slds-picklist">
<apex:selectList id="countries" value="{!slackChannel}" size="1" required="true" styleClass="slds-input">
<apex:selectOptions value="{!ListOfSlackChannels}"/>
</apex:selectList>
</div>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__row slds-align_absolute-center ">
<label class="slds-form-element__label " for="sample2"> Name </label>
<div class="slds-form-element__control slds-picklist">
<apex:inputTextArea value="{!slackTextMessge}" id="sample1" styleClass="slds-input"/>
</div>
</div>
</div>
</div>
</apex:outputPanel>
<div class="slds-form-element slds-align_absolute-center">
<button onclick="postSlackMessage();" styleClass="slds-button slds-button_neutral">Post to Slack </button>
<button onclick="closeAction();" styleClass="slds-button slds-button_neutral">Close </button>
</div>
</apex:form>
</div>
</apex:page>
And the controller is here.
public class GlobalSlackActions {
public String slackChannel {get;set;}
public List<SelectOption> channelNameOptions{get;set;}
public String slackTextMessge {get;set;}
public String slackToken {get;set;}
public GlobalSlackActions(){
slackToken ='xoxp-167092741267-167199659508-179751455458-6fd12a391bd432b735b4efcb1313193f';
}
public List<SelectOption> getListOfSlackChannels () {
String slackEndpoint = 'https://slack.com/api/channels.list?token='+slackToken;
HttpResponse res = buildHttp(slackEndpoint);
if(res.getStatusCode() ==200){
JSON2Apex cls = (JSON2Apex)parse(res.getBody());
list<Channels> c =cls.channels ;
System.debug('c'+c);
List<SelectOption> options = new List<SelectOption>();
for(Channels cName :c){
options.add(new SelectOption(cName.name,cName.name));
}
return options ;
}else{
return null ;
}
}
public class JSON2Apex {
public Boolean ok;
public List<Channels> channels{get;set;}
}
public class Channels {
public String id;
public String name{get;set;}
public Boolean is_channel;
public Integer created;
public String creator;
public Boolean is_archived;
public Boolean is_general;
public Integer unlinked;
public String name_normalized;
public Boolean is_shared;
public Boolean is_org_shared;
public Boolean is_member;
public Boolean is_private;
public Boolean is_mpim;
public List<String> members;
public Integer num_members;
}
public static JSON2Apex parse(String json) {
return (JSON2Apex) System.JSON.deserialize(json, JSON2Apex.class);
}
public PageReference postMessagetoSlack () {
String slackEndpoint = 'https://slack.com/api/chat.postMessage?token='+slackToken+'&channel='+slackChannel+'&text='+slackTextMessge+'&pretty=1';
buildHttp(slackEndpoint);
return null ;
}
public HttpResponse buildHttp(String url){
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('POST');
HttpResponse res = new HttpResponse();
res = h.send(req);
return res ;
}
}
Go to set up, find global actions and create a new one as shown below.

Add to the publisher layout as shown below.

After saving the publishers layout you can able to see the quick actions as shown below.

Object Specific actions
Now I am going to walk thru how to create the object specific action.To associate an action to object you need to user standardController attribute of the object. Here we are going to create a Case Quick actions which are allowing the user to take the ownership of the case from case queue.
Here is the visual force page
<apex:page standardController="Case" extensions="CaseTakeOwnership" showQuickActionVfHeader="false">
/canvas/sdk/js/publisher.js
<apex:form id="demo">
<apex:actionFunction action="{!takeOwnership}" name="takeOwner" reRender="demo" oncomplete="refreshFeed();"/>
<div style="align:center">
<br/><br/><br/>
<button onclick="takeOwner();" class="sucessBtn">Take Ownership</button> <br/><br/><br/><br/>
<button onclick="closeAction();" class="closebtn">Cancel</button>
</div>
</apex:form>
</apex:page>
The controller is here below.
public class CaseTakeOwnership {
public Case careRecord {get; set;}
public CaseTakeOwnership(ApexPages.StandardController controller) {
careRecord =(Case)controller.getRecord();
}
public PageReference takeOwnership() {
try {
careRecord.OwnerId = UserInfo.getUserId();
update careRecord;
} catch(Exception ex){
}
return null ;
}
}
Both in global action and Object actions, I set showQuickActionVfHeader to false. So that we will not able to see the Standard Submit and Cancel Global action header.
Now go to Case Object buttons and links and create a new action as shown below
Add the object to quick action, salesforce 1 and lightning action on page layout based on whether you wanted to show on salesforce class or salesforce 1 as shown below.

Publisher Events
Refresh feed (desktop)
Sfdc.canvas.publisher.publish({ name: 'publisher.refresh',
payload: {feed:true}
});
Submit hook (Salesforce1)
Sfdc.canvas.publisher.subscribe({name: "publisher.showPanel",
onData:function(e) {
Sfdc.canvas.publisher.publish({name:
"publisher.setValidForSubmit", payload:"true"});
}});
Sfdc.canvas.publisher.subscribe({ name: "publisher.post",
onData: function(e) {
alert("call some remote action here");
Sfdc.canvas.publisher.publish({ name: "publisher.close",
payload:{ refresh:"true" }});
}});
Close publisher event
Sfdc.canvas.publisher.publish({name: "publisher.close", payload:{ refresh:"true" , successMessage: 'Cancel!'}});
Activate publish button
Sfdc.canvas.publisher.publish({
name: "publisher.setValidForSubmit",
payload:"true"});
Clear Panel State
Sfdc.canvas.publisher.subscribe(
{ name : "publisher.clearPanelState", onData:function(e) { alert('Fire ClearPanelState'); }}
);
Show Panel State
Sfdc.canvas.publisher.subscribe(
{ name : "publisher.showPanel", onData:function(e) { alert('Fire ShowPanel'); }}
);
Success State
Sfdc.canvas.publisher.publish({ name : "publisher.success", payload : { feed:true }});
Redirect (Salesforce1)
sforce.one.navigateToSObject(recordId,view)
sforce.one.navigateToURL(url)
sforce.one.navigateToFeed(subjectId, type)
sforce.one.navigateToFeedItemDetail(feedItemID)
sforce.one.navigateToRelatedList(relatedListId, parentRecordId)
sforce.one.navigateToList(listViewId, listViewName, scope)
sforce.one.createRecord(entityName, recordTypeId)
sforce.one.editRecord(recordId)