Apex Class as action

This would be really really cool. The ability to call a class. Specifically for connecting to trigger-ready flows using the start() method in apex. Action Name: Apex Class Lookup function for Apex Class Display inputs required for Class. (most of the time all that would be required would be an Id) This would allow programming to be done almost completely declaretively. Not only that we could set when to run the code. On model save, on button click, etc

Also, javascript snippets call apex classes?

Great idea, we have been considering doing this since Skuid was first created. For this to work, we would have to do either of the following:

(a) support several of the most common interfaces, such as:
 - Schedulable - execute()
 - Batchable - start()
 - Process.Plugin - invoke()
 - Flow.Interview  - start()

(b) create our own interface that we would expect others to implement, such as:

global interface Executable {
    String execute(String params);
}

hehehehe … that mostly went over my head. :smiley:

So is this possible and/or likely to ever happen?

In the Chicago training right now, it looks like this is implemented in Banzai… not sure which way they managed to make it happen. 

How about Calling Flow as action. Would be awesome too!

The Banzai release allows you to run Invocable Apex Actions from the Action Framework. Apex can be defined as “invocable” using the @InvocableMethod annotation. 

Ok. My first foray into this and I’m surely missing something.

Can you provide documentation on this method. skuid.sfdc.api.makeRequest

I think it’s what I need to use to send a BLOB through to the class. I tried the Skuid action “Run an Apex Action” and get the following error.

Here’s the test page. The class is what you’d expect. :wink:

<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true"> <models> <model id="Contact" limit="1" query="true" createrowifnonefound="false" adapter="" type="" sobject="Contact"> <fields> <field id="Id"></field> </fields> <conditions></conditions> <actions></actions> </model> </models> <components> <pagetitle model="Contact" uniqueid="sk-1NII09-102"> <maintitle> <template>{{Name}}</template> </maintitle> <subtitle> <template>{{Model.label}}</template> </subtitle> <actions> <action type="multi" label="Attach File"> <actions> <action type="sfdc-custom-apex" sfdcactionname="UploadFileClass"> <inputs xmlns="http://www.w3.org/1999/xhtml"> </inputs> </action> </actions> </action> </actions> </pagetitle> </components> <resources> <labels></labels> <javascript></javascript> <css></css> </resources> <styles> <styleitem type="background" bgtype="none"></styleitem> </styles> </skuidpage>

I’m not used to looking at the XML for this, and even so I could be totally wrong here, but it looks like Apex would have trouble reading your input as a List (InvocableMethod needs to receive a list and return a list). I’ve had trouble working in run Apex action because of that limitation and end up just using sforce.apex.execute an reworking my InvocableMethod as a webservice.

Some clear examples of what would go in that input field would be super helpful!

J. gave me one example here but I had already switched to webservice and haven’t tried it yet…

Ok. Each input as their own list or all inputs in one list. I’d assume the former. If so, I can’t see how a single input value would look different than a single input list with a single value.

First need to be be able to set the input value for a BLOB. I was hoping for a popup to be automatically generated, but that was wishful thinking. :stuck_out_tongue:

I’m not sure if this is helpful, but I think you should still be able to call an invocable method and pass in single arguments, rather than lists. The syntax is not exactly what you would expect. Here’s an example of an invocable method that runs an approval process action on a record (in my case, a Case record), and can be called from Skuid.

global class CaseApprovalActions {
    
    @InvocableMethod(label='Approve Record')
    global static List<approveresponse> approveRecord(List<approverequest> requests) {
    List<approveresponse> responses = new List<approveresponse>();
    ApproveResponse res = new ApproveResponse();
    responses.add(res);
    
    ApproveRequest req = requests[0];
    
    ProcessInstanceWorkItem item = [SELECT Id FROM ProcessInstanceWorkItem WHERE Id = :req.workItemId LIMIT 1];
    
    if (item.Id != null &amp;&amp; (req.actionType == 'approve' || req.actionType == 'reject')) {
        Approval.ProcessWorkItemRequest pwr = new Approval.ProcessWorkItemRequest();
        pwr.setWorkItemId(item.Id);
        
        if (req.actionType == 'approve') { pwr.setAction('Approve'); }
        else if (req.actionType == 'reject') {pwr.setAction('Reject'); }
        
        pwr.setComments(req.comments);
        
        Approval.process(pwr);
    }
    
    return responses;
}

global class ApproveRequest {
    @InvocableVariable(required=true description='The pending Work Item Id to approve/reject' label='Work Item Id')
    public Id workItemId;
    
    @InvocableVariable(required=true description='Comments on why the user is approving/rejecting the record' label='Comments')
    public String comments;
    
    @InvocableVariable(required=true description='Options are "approve", "reject"' label='Action Type')
    public String actionType;
}

global class ApproveResponse {
    @InvocableVariable
    public String message;
}

}

You just need to set up a class (e.g. ApproveRequest) for the List type to pass into the method, and then for every @InvocableVariable defined in the class, you can pass in a value from Skuid.

Skuid button configuration: