Oh my god. It's full of code!

Posts tagged “script

Salesforce Apex Script Loader

I’m working on a new tool that may or may not be useful but I’ll explain a little about why it came to exist, what it does and you can decide if it has any value for you or not.

Problem: I have a task that I need to do in our production org each day. I must find any cases that have a certain status, change the status, then change them back to re-trigger a back end process. This is obviously a menial task but can be rather annoying to do if there are more than a few records.

Solution: Write an execute anonymous script to find the cases, modify them as needed and save them back. Easy enough (it’s our prod org and writing a new batch/schedulable class to handle this temporary issue would never fly).

Next Problem: I don’t really like having to log in to the org, open the dev console and run the script. Even that seems like it takes too much time and I actually have to remember to do it. I’d rather just have it all handled automatically.

Next Solution: SFDX allows you to run saved script files against an org you have authenticated against. I can write a simple shell script that can be scheduled and calls my script. The script can handle the work and send me an email with the results incase I’m asked how the queue was that day.

Next Problem: I like to over engineer things when I’m having fun and couldn’t leave well enough alone.

Next Solution: I write an over complicated yet flexible node JS wrapper that I’m calling the Apex Script Loader that is meant to allow numerous different pre saved scripts with their own configurations and even injectable variables for some reason.

You: “Wait, why?”

Me: “Because it was fun and I’ve haven’t had much interesting work to do recently okay?”

So a bit more about how this works. Say you have a script you need to run daily and want to just run it from your desktop instead of needing a scheduled class. Here is what you could do.

  1. Ensure you have Node installed and SFDX installed and your desired org authorized.
  2. Download my Apex Script Loader
  3. Make a new folder to contain your script and the config file.
  4. Write your Apex script and save it in that folder
  5. Copy the sample config file and change your username and other details as needed.
  6. Test that it runs by simply running ‘node ApexScriptLoader.js YourFolderNameHere’
  7. Watch it do it’s thing.
  8. Use the task scheduler on your desktop to run the command whenever you like.
  9. Say “huh, that’s neat” then promptly forget it exists because it’s hardly useful.

But wait you say –

“My script needs to pull in data from some external source and that execute anonymous script can’t access anything on my local file system! Furthermore there is no way to pass data into the script so it’s basically living in a black box aside from what it can query from Salesforce!”

Chill bruh. That’s where my insane over thinking comes in handy. I’ve added a ‘variable injection’ feature that lets you provide as many variables as you like in JSON format via a ‘variables.json’ file (name configurable in the config file). In that file you can provide as many key/value pairs as you like and when the Script Loader runs it will process those and inject them into your Apex script making them available in the runTimeVars variable. So now whatever other processes you have simple need to modify that file adding in their values and your script can access them. Pretty cool huh? I figure later on I’ll probably add the ability to read from multiple files so if you have multiple systems all providing values they aren’t fighting over the file but we’ll see if anyone actually even needs that.

Sample output of the script loader (after that it started printing actual org data so I cut it off)
Sample Configuration File so you can see what variables you can configure
What the variables.json file looks like. You can add as many as you like and of any type supported in JSON
Here you can see what the actual Apex script looks like after the variables have been injected at run time.

If you want to check it out, you can grab it over at https://github.com/Kenji776/ApexScriptLoader

The included sample script does not modify your org in any way, I’ve commented out the update statements so you can run it without fear. It will send you an email when it’s done so you know it ran (if you have it scheduled on a dumb terminal somewhere). Also, I’ve only included a bat file for invoking the script, but it’s literally 3 lines so I’m pretty sure you can write your own version for linux/mac/smart fridge/whatever if you need.

I literally just wrote this today in like the last few hours so there are probably some bugs and less than optimal approaches but I can feel myself already losing interest so I figured I should probably post something before this ends up in the heaps of interesting projects that never see the light of day. Let me know if you have questions are can think of any handy features.

Anyway, hope this helps someone. Till next time.

-Kenji


Reliably injecting jQuery and jQuery UI with callback!

Hey all,
So this is kind of a cool thing. Sometimes you end up needing to inject jQuery in a page (like with advanced custom buttons in Salesforce) or in other cirumstances where you can write scripts, but you don’t have direct access to the source doc. Some of these times you want to include jQuery, along with jQuery UI and it’s CSS. Most of us know you can use the head.addScript function of javascript to inject the code, but how do you know when it’s loaded? How do you make sure you only load the UI library after the core library has loaded? Well worry no more, as I have an awesome javascript function here to reliably inject jQuery and the UI and then call a function of your choosing. Here ya go!

function loadJQuery(callback)
{
    try
    {
        if(typeof jQuery == "undefined" || typeof jQuery.ui == "undefined")
        {
            var maxLoadAttempts = 10;
            var jQueryLoadAttempts = 0;
            //We want to use jQuery as well as the UI elements, so first lets load the stylesheet by injecting it into the dom.
            var head= document.getElementsByTagName('head')[0];
            var v_css  = document.createElement('link');
            v_css.rel = 'stylesheet'
            v_css.type = 'text/css';
            v_css.href = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css';
            head.appendChild(v_css);

            //Okay, now we need the core jQuery library, lets fetch that and inject it into the dom as well
            var script= document.createElement('script');
            script.type= 'text/javascript';
            script.src= 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
            head.appendChild(script);
                    
            checkjQueryLoaded = setInterval(function()
            {             
                if(typeof jQuery != "undefined")
                {
                    //Okay, now we need the core jQuery UI library, lets fetch that and inject it into the dom as well
                    var script= document.createElement('script');
                    script.type= 'text/javascript';
                    script.src= 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js';
                    head.appendChild(script);
                    window.clearInterval(checkjQueryLoaded);
                }
                else if(maxLoadAttempts < jQueryLoadAttempts)
                {
                    window.clearInterval(checkjQueryLoaded);
                }
                jQueryLoadAttempts++;
            },300);
            
            jQueryLoadAttempts = 0;        
        
            checkLoaded = setInterval(function()
            {             
                if(typeof jQuery != "undefined" && typeof jQuery.ui != "undefined")
                {
                    window.clearInterval(checkLoaded);
                    callback(true);
                }
                else if(maxLoadAttempts < jQueryLoadAttempts)
                {
                    window.clearInterval(checkLoaded);
                    callback(false);
                }
                jQueryLoadAttempts++;
            },500);
        }
    }
    catch(exception)
    {
        callback(false);
    }
}

Then you can invoke it and have a callback like this

loadJQuery(function(loadSuccess){
    if(loadSuccess)
    {
	//Do your jQuery stuff here. Basically you can think of this as a replacement for your 
	//document.onReady code
        $(document.getElementsByTagName('body')[0]).append("<div id=infoNotice title='Success'>jQuery and jQuery UI loaded!</div>"); 
        $( "#infoNotice" ).dialog({ modal: true});  
    }
    else
    {
        alert('Couldn\'t load jQuery :(');    
    }
});

Have fun!