<< Previous | Home | Next >>

Deploy your own Salesforce Workbench on Heroku at the click of a button

The other day Salesforce Workbench was having issues. Generally it kept returning errors and SOQL queries took forever and timed out. Now Salesforce Workbech is a LAMP app that runs on Heroku and it turns out it is actually possible to deploy your own instance on Heroku using a simple Heroku Button. To do this simply follow the below steps (you need to have an account but if you don't simply sign up):

  1. Go to the project page at https://elements.heroku.com/buttons/jdrishe/salesforce-workbench
  2. Click the Deploy to Heroku button (use the button on the bottom and not the one on the top right as the one on the top right deploys and older version)
  3. Log into the deployed app (remember to add your security token after the password but I guess you knew that!!) and you are done!
Now you have your own instance of Salesforce Workbench running on Heroku. So nice. Below is a small video I recorded showing the actual steps and realtime - just over a minute and you have your own instance! Boom!!

Currency conversion in Apex

While waiting for my flight in the lounge tonight I was playing around with currencies in Salesforce because - why not... Conversion between configured currencies are supported in SOQL and Salesforce but only between the configured corporate currency and the users personal currency. But what if you want to convert between an opportunity amount in one currency and into another currency using the configured conversion rates in Salesforce? Well there is no support for this. So as an Apex / SOQL self-assignment I wrote the below class to do that. Basically it lazily reads in configured currencies and allows you to convert between any currency, from a supplied currency to the corporate currency or from a supplied currency to the users own currency. For extra credits it follows the decimal places configured in the Salesforce Setup.

Please note code is provided as-is without any warrenties or guarantees. As a friend always writes --- YMMV....

public class CurrencyConverter {
    private Map conversions = null;
    private String corporateIso = null;
    private String userIso = null;
    
    /**
     * Initialize corporate currencies setup in Setup.
     */
    private void initCorpCurrencies() {
        // build once only
        if (null != this.conversions) return;
        
        // build map
        this.conversions = new Map();
        final List currencies = [select Id, IsCorporate, IsoCode, ConversionRate, DecimalPlaces from CurrencyType where IsActive=true];
        for (CurrencyType cur : currencies) {
            this.conversions.put(cur.IsoCode, cur);
            if (cur.IsCorporate) this.corporateIso = cur.IsoCode;
        }
    }
    
    /**
     * Read user currency from users preferences.
     */
    private void initUserCurrency() {
        // load only once
        if (null != this.userIso) return;
        
        // get user currency ISO and store it
        List users = [SELECT DefaultCurrencyIsoCode FROM User WHERE Id =: UserInfo.getUserId()];
        if (null == users || users.size() != 1) {
           throw new UnknownUserException('Could not find user record for active user <' + UserInfo.getUserId() + '>');
        }
        this.userIso = users[0].DefaultCurrencyIsoCode;
    }
    
    /**
     * Get corporate currency.
     */
    public String getCorporateISO() {
        this.initCorpCurrencies();
        return this.corporateIso;
    }
    
    /**
     * Get user currency.
     */
    public String getUserISO() {
        this.initUserCurrency();
        return this.userIso;
    }
    
    /**
     * Convert from supplied currency to corpotate currency.
     */
    public Decimal convertToCorporateCurrency(Decimal value, String fromIso) {
        return this.convert(value, fromIso, this.getCorporateIso());
    }
    
    /**
     * Convert from supplied currency to users currency.
     */
    public Decimal convertToUserCurrency(Decimal value, String fromIso) {
        return this.convert(value, fromIso, this.getUserISO());
    }
    
    /**
     * Convert between two known currencies.
     */
    public Decimal convert(Decimal value, String fromIso, String toIso) {
        if (String.isEmpty(fromIso) || String.isEmpty(toIso)) {
            return value;
        }
        this.initCorpCurrencies();
        
        // ensure valid to/from ISO
        if (!this.conversions.containsKey(fromIso)) {
           throw new UnknownCurrencyException('Unable to find active from ISO currency <' + fromISO + '>');
        }
        if (!this.conversions.containsKey(toIso)) {
           throw new UnknownCurrencyException('Unable to find active to ISO currency <' + toISO + '>');
        }
        
        // if same currencies we simply round
        if (fromIso.equalsIgnoreCase(toIso)) {
            return value.setScale(this.conversions.get(fromIso.toUpperCase()).DecimalPlaces, System.RoundingMode.HALF_UP);
        }
        
        // get values and then rate
        final CurrencyType fromCur = this.conversions.get(fromIso.toUpperCase());
        final Decimal fromRate = fromCur.ConversionRate;
        final CurrencyType toCur = this.conversions.get(toIso.toUpperCase());
        final Decimal toRate = toCur.ConversionRate;
        final Decimal rate = toRate/fromRate;
        
        // calc
        final Decimal result = value * rate;
        final Decimal resultRounded = result.setScale(toCur.DecimalPlaces, System.RoundingMode.HALF_UP);
        
        // return
        return resultRounded;
    }
    
    public class UnknownUserException extends Exception {
        
    }
    
    public class UnknownCurrencyException extends Exception {
        
    }
}

Simplifying usage of Salesforce Lightning Design System using NPM and Express

Using Salesforce Lightning Design System (SLDS) is a great and easy way to add some super nice styling to your app. It comes with some nice defaults and a responsive grid system like other frameworks lige Bootstrap. Where SLDS really shines is of course if you are already using Salesforce (I assume you're already on Lightning right?!!?!?) or if you are going to. And again who isn't. Anyways... Using SLDS makes your apps really look like Salesforce which is nice for Salesforce Lightning Components or for an app using Lightning Out to host Lightning apps in external applications.

I often use SLDS for another use-case which is quickly doing a mockup for a new Lightning Component. Doing it in SLDS can often be way quicker than making by hand from scratch or attempting to draw the component using Powerpoint or other tool.

Previously I've been using the download option for SLDS ie. grabbing the package of the website, expanding and copying into my app. Today I tried out the NPM solution as I often use node.js and Express when I need to mock stuff up. Installing SLDS is as easy as doing a "npm install @salesforce-ux/design-system --save" and you're all set. Mostly. Problem is of course that the assets you need end up in the node_modules directory which is not exposed outside the app. The way I get around it is to add a static-rule to my Express server.js as follows:

const app = express();
app.use('/slds', express.static(__dirname + '/node_modules/@salesforce-ux/design-system/assets'));
Then loading SLDS assets into my app is as easy as:
<link rel="stylesheet" type="text/css" href="/slds/styles/salesforce-lightning-design-system.css" />

This works great if/when you post your app to Heroku as well and has the additional benefit of easy version management using NPM and package.json.

Salesforce week 25-27 and finishing this weekly thing...

Wow!! A half year has gone by. Half a year... Where did the time go? Over the last weeks I've gradually noticed that my view on being with Salesforce has shifted from being "something new" to being "how things are". On feeling at home in the organisation and that I know my place. Does new things come up sure but it's feeling less and less like every day brings something new, a new badge or a new process. I've settled into the #Ohana. This is also why I've decided to stop writing these weekly posts and go back to writing "normal" blog posts. I still have a V2MOM goal of blogging once a week on average over my first year and I'm no track to meet that goal.

That being said being part of the organisation has also taught me just how much we need more people - the right people. I think it's safe to say that we are constantly hiring so if you're looking for something new reach out to me and I'll be more than happy to talk and discuss what Salesforce is, which positions are open and how it's like working for Salesforce.

In 3 weeks I'll be heading off to my first off-site where the entire Salesforce CSG EMEA North will meet up in Barcelona for 3 days of training, networking and fun. Should be very nice disregarding that I'm flying out at 7am on Sunday and will probably go directly to the airport from a major party. Oh well - there's time to sleep on the plane.

Top 5 from my first 6 months

  • Develop on the new Salesforce Lightning and become quite good at it
  • "Master" Salesforce and become 5 times Salesforce certified
  • Bootcamp in San Francisco
  • Delivering real business value at my customer and doing it with Lightning
  • Working with very nice and talented people

Status after this week

Trailhead points: 85325
Trailhead badges: 100
Certifications: 5 (Salesforce Certified Administrator, Salesforce Certified Platform App Builder, Salesforce Certified Advanced Administrator, Salesforce Certified Sales Cloud Consultant, Salesforce Certified Service Cloud Consultant)

Tags :

Salesforce Lightning Component API change

As we get closer to Summer 17 we start using difference versions across production instances and sandboxes. This of course also leads to opportunities for differences in API's... I just found one such difference as I'd been developing some Lightning components on Summer 17 and got errors when trying to run them on Spring 17. In Summer 17 you can do the following in a client-side event handler to get the DOM element of the source component:

({
   react: function(component, event, helper) {
      const elem = event.getSource().getElement();
   }
})
This doesn't work in Spring 17 as the getElement method is not available. So find another way to accomplish whatever you are doing there...

Using component.find in Salesforce Lightning Components

When developing Salesforce Lightning Components you very often use the aura:id attribute on components to tag them and component.find to find them again. This works very well and is documented nicely in the documentation (Finding Components by ID). If however you tag a component using aura:id in an iterator you may not know how many resulting components will be on the page. The component.find method may return undefined (if no matching components), a component instance (if a single match was found) or an array of component instances if multiple components with a matching aura:id was found. This is fine but if you want to loop over any found component Javascript may give you a headache as the resulting variable may contain an array or an object instance. Hmmm... You can either using Vanilla Javascript to figure out whether it's array (or cheat and use $A.util.isArray) and write code for the array case and code for the single instance case --- or you can take the short route.

I always take the short route...

Say you had markup like this using an aura:iteration component to loop over a variable containg 0, 1 or many values.

<aura:iteration var="item" items="{!v.items}">
	<lightning:input type="checkbox" label="{!item}" aura:id="mycheckbox" />
</aura:iteration>

Contrast the approach using "isArray"

const cmps = component.find("mycheckbox");
if (!cmps) return;
if ($A.util.isArray(cmps)) {
    cmps.forEach(cmp => {
        // do stuff...
        cmp.set("v.checked", true);
    })
} else {
    // do stuff on the instance
    cmp.set("v.checked", true);
}
...to the approach of simply concatenating into an array... I find this much nicer, cleaner and it avoids the duplication of code between the single instance and array case. If I know there would always be at least one component it could even be done on a single line i.e. loose the undefined check on the second line. Javascript terse-ness heaven!!
const cmps = component.find("mycheckbox");
if (!cmps) return;
[].concat(cmps).forEach(cmp => cmp.set("v.checked", true));

! vs # in Salesforce Lightning Components

Often when you read tutorials on developing Salesforce Lightning components they all contains expressions when passing data and variables into other components. Like say you have an attribute as an array and would like to iterate over the elements:

<aura:attribute name="arr" type="string[]" default="['foo', 'bar', 'baz']" />

<ul class="slds-list--dotted">
<aura:iteration items="{!v.arr}" var="item">
    <li>{!item}</li>
</aura:iteration>
</ul>
Now this is a very simple example but it shows the point. This component shows a simple bullet list with items - when the array attribute ("arr") changes the list will recalculate and update. Often this is what you want but sometimes the array will never change. A better way to do this - especially with arrays as Javascript has not easy / performant way to see if an array actually changed - is to use # instead of ! in your expressions. # means that the expression will not automatically update when the attribute is changed which may speed things up considerably when there are many attributes and many components on the page. Fewer attributes to monitor for changes by the framework leads to better perfornance.
<aura:attribute name="arr" type="string[]" default="['foo', 'bar', 'baz']" />

<ul class="slds-list--dotted">
<aura:iteration items="{#v.arr}" var="item">
    <li>{#item}</li>
</aura:iteration>
</ul>
Another reason for using # instead of ! could be to control the data binding between parent and child components.

There is a nice article on the matter in the Salesforce documentation - Data Binding Between Components.

Salesforce week 24

Last week was all about getting the next component for my customer into production. For one of their business lines they had some very specific requirements for a search so we built a search from scratch. Now Salesforce comes with a built in fulltext search functionality but the customer only wanted results from a specific object type and a specific record type at that. So that's what we built. The solution was deployed on Thursday and have been running since. Main hickup in the deployment was some weird "cannot access childNodes of null" errors that kept surfacing from the Lightning component I built to display what search filters were in place. The component was basically just a wrapper around a number of arrays showing the filters as pills and showing a filter count. The markup was basically like this (c:Pill is simply a wrapper component for the pill):

<div class="filters">
    <div>{!v.filtersCount} filters added</div>
    <div aura:id="filters_expand" class="">
        <aura:iteration var="filter" items="{!v.accountDisplayObjects}">
            <c:Pill displayText="{#filter.displayText}" object="{#filter}" colorClass="orange" />
        </aura:iteration>
        ...
        ...
        <aura:iteration var="filter" items="{!v.geoDisplayObjects}">
            <c:Pill displayText="{#filter.displayText}" object="{#filter}" colorClass="lightorange" />
        </aura:iteration>
    </div>
</div>
We kept however getting the errors and I narrowed down the issue to being with the aura:iteration components and if multiple subsequence display object arrays were being changed after one another. The fix turned out - as always - to be very simple. I simply wrapped each aura:iteration component in its own span-tag.
<div class="filters">
    <div>{!v.filtersCount} filters added</div>
    <div aura:id="filters_expand" class="">
        <span><aura:iteration var="filter" items="{!v.accountDisplayObjects}">
            <c:Pill displayText="{#filter.displayText}" object="{#filter}" colorClass="orange" />
        </aura:iteration></span>
        ...
        ...
        <span><aura:iteration var="filter" items="{!v.geoDisplayObjects}">
            <c:Pill displayText="{#filter.displayText}" object="{#filter}" colorClass="lightorange" />
        </aura:iteration></span>
    </div>
</div>
Oh well another bug bites the dust and another lesson learned...

Besides this we got a new team member as another one of the existing team members is graduating into management. So now we also have a Salesforce Business Architect from the UK office. Nice.

What did I learn

  • Span your aura:iteration components
  • Troubleshooting Lightning Style
  • There is a reason for having a staging environment but make sure it contains representative data...

Status after this week

Trailhead points: 85325
Trailhead badges: 100
Certifications: 5 (Salesforce Certified Administrator, Salesforce Certified Platform App Builder, Salesforce Certified Advanced Administrator, Salesforce Certified Sales Cloud Consultant, Salesforce Certified Service Cloud Consultant)

Tags :