Flows vs. Form Factor

Ever had the need to make a Flow responsive based on the form factor in which it executes? Today the Flow run-time cannot readily determine the form factor of the client it’s executing within. However, having a Lightning Web Component (though similarly this would be possible with Aura) we do have access to the form factor, using the @salesforce/client/formFactor scoped module.

I created this tiny Lightning Web Component which does two things:

  1. It determines the form factor (e.g. ‘Large’ or ‘Small’, Salesforce has only these two flavors today);
  2. When the form factor is determined it navigates to the next screen element in the Flow.

The latter is optional, using an Input argument. Simply drop the Lwc on a blank screen element (the first?) of your flow. And have the next step branch based on the outputted form factor.

import { LightningElement, api } from 'lwc';
import { FlowAttributeChangeEvent, FlowNavigationNextEvent } from 'lightning/flowSupport';
import FORM_FACTOR from '@salesforce/client/formFactor';

export default class FormfactorFlowHelperLwc extends LightningElement {

    @api availableActions = [];         // Populated by lightning/flowSupport
    @api autoNavigate = false;          // Input. Should the Lwc execute the Flow's navigate event?
    @api formFactor = '';               // Output. Form factor.

    connectedCallback() {
        this.setFormFactor();
        if (this.autoNavigate) {
           this.navigate();
        }
    }

    setFormFactor () {
        const attributeChangeEvent = new FlowAttributeChangeEvent('formFactor', FORM_FACTOR);
        this.dispatchEvent(attributeChangeEvent);
    }

    navigate () {
        if (this.availableActions.find(action => action === 'NEXT')) {
            const navigateNextEvent = new FlowNavigationNextEvent();
            this.dispatchEvent(navigateNextEvent);
        }
    }
}

Grab it here, and deploy it to your org.

https://github.com/JeroenSfdc/sfdx-flow-formfactor-helper-lwc

Hands-on With the Salesforce Metadata Dependency API

I needed to quickly analyze the potential impact of one of the Salesforce Critical Updates, which is going to auto-activate per December 2nd 2019:

Improve Security by Requiring User Access to Apex Classes Invoked by Flow (Critical Update)

Different options of course:

  1. Go all manual. Review all flows and process builder meticulously. Maybe not so efficient.
  2. Check which @InvocableMethod‘s live in the Org.
  3. Use the Dependency API!

That latter option (of course) I deemed would be best. The Metadata Dependency API has become GA with the Winter ’20 release. The timing is perfect (sometimes). Wanna learn moar about it? Check this blog post.

So what to do? Ideally I wanted to get a list of all Flows having a reference to any Invocable method. The nice thing is, the Dependency API is accessible through SOQL using the Tooling API. That comes in handy. Of course there are limitations as to how to query. No groupings, maximum 2,000 results, and limited WHERE clauses. That said, the following query seemed to work nicely from the Developer Console.

SELECT MetadataComponentName, MetadataComponentType, RefMetadataComponentName 
FROM MetadataComponentDependency 
WHERE RefMetadataComponentType = 'ApexClass' AND MetadataComponentType = 'Flow'

But since several classes where used in many different Flows, and also Inactive flows are considered by the Dependency API I needed to have the output in a comma-separated form to quickly run a pivot table.

SFDX CLI to the rescue!

The nice thing about the SFDX CLI is that it’s being improved on a hyper-frequent basis. The CLI can run SOQL against the Tooling API and can format the output as CSV. What more do we need?

sfdx force:data:soql:query 
-q "SELECT MetadataComponentName, MetadataComponentType, RefMetadataComponentName 
FROM MetadataComponentDependency 
WHERE RefMetadataComponentType = 'ApexClass' 
AND MetadataComponentType = 'Flow'"  
--resultformat csv 
-u jburgers@xxxxxxxx.com.uat 
--apiversion 47.0 -t

Spool the output to a file and Bob’s your Uncle!

Increase Salesforce Overlays With The Lightning:backgroundUtilityItem Interface

Mmm… Should I blog this? Ok, let’s go for it. I should probably put a large “at your own risk” disclaimer. Recently I fooled around while developing a Flow, launched as tradition Quick action. Goal was to increase the width of the Quick action its overlay. Recently I already managed to use a CSS-hack to increase the width for Lightning Component Quick Action, so I thought – let’s give it a spin for a Flow as well. 

Here we go, 70% width

Basically, what I managed to do is create a static CSS resource, and use the <ltng:require/> tag to load it. 

<ltng:require styles="{!$Resource.popupCSS}"/>

The popupCSS static resource contains the CSS-hack (yeah, using !important which is against the book…). 

.slds-modal__container{
     max-width: 70% !important;
     width: 70% !important;
 }

In this case, the CSS-hack increases the width of the modal window identified by the class ‘slds-model__container’ to 70% of the available screen’s real-estate. 

Now, this works fine for any custom Lightning Quick Action Lightning Component. And it’s locker-safe as well, as it will download the popupCSS resource only within the DOM of the Lightning component in which it’s specified. Cool.

But now back to the Modal dialog for the Flow Quick Action. I just wrapped the <ltng:require/> tag within another Lightning component. 

<aura:component implements="lightning:availableForFlowScreens" description="Flow component to embed a named CSS static resource">
    <ltng:require styles="{!$Resource.popupCSS}"/>
</aura:component>

Using the Flow-specific interface “lightning:availableForFlowScreens” to enable it within Flows. And guess what, the moment I embedded this component on the first screen of the flow, it effectively applied the CSS-hack. 

Including CSS-hack in the flow…

So mmm… this works. But with a “side-effect” that the CSS-hack would apply  everywhere in the app once it got loaded. Every Dialog (Edit record, new record, …) would take the 70% width.

That brought me to the next ‘experiment’ is to by-default have the CSS-hack to take effect. And guess what? The Winter ’19 “lightning:backgroundUtilityItem” Lightning component interface does just that. The lightning:backgroundUtilityItem interface allows:

“… a component to be used as an app-level component that is created when the app loads, and runs code without rendering itself in the app UI.”

<aura:component implements="lightning:backgroundUtilityItem" description="Popup Width Background Utility Component">
    <c:PopupCssResourceComp/>
</aura:component>

Once done, just add it to the Lightning’s App list of Utility Items. It will load, as soon as the App is loaded. 

Again, beware of the disclaimer. I have not tested this under ‘production’ circumstances, and it will have an App-wide effect! Nevertheless, experimentation means learning, right?

Enjoy!

Lighting Out + Visualforce = Lightning Printing

Ever needed to print from within Lightning Experience? Recently we developed for our customer an Account summary page consisting of a number of filterable related lists. For that purpose I tried-out and successfully implemented a solution using the CMDT Enhanced Related List package managed package. Developed by my colleague and peer Denny Chandra from Down-under. It’s a terrific solution, extremely easy and super versatile. With little code, only Lightning markup and a tiny bit of Lightning controller code, a I was able to create a nice dynamic user-experience. The purpose of this post isn’t to explain this particular solution, I got the request to have printable version of the data presented. Which factually is just a bunch of related lists.

account360sr

The next challenge came around the corner, when the customer asked to create a printable page of the presented data. Since the Account Summary is just a single self-contained Lightning Component I questioned myself whether it be feasible to create a Visualforce page? And yes, the merits of Lightning is that Lightning applications can also be exposed externally. That is what Lightning Out brings us. Fuse Lightning Out and Visualforce, and you got yourself a potential solution. Fusing both is really simple. And you could read more documentation here. But beware, speaking today, Lightning Out is still a beta feature, so its implementation might change before getting the general available stamp.

That said… The hosting Lightning app needs to be extended.

<aura:application
        extends="ltng:outApp"
        access="global"
        description="AccountSummaryApp"
/>

The Visualforce page, in this case only has to include a single component. Important to include the directive. Other than that, it pretty much boiler plate as per documentation.

<apex:page sidebar="false" showHeader="false" standardStylesheets="true" controller="AccountSummaryController" >

    <apex:includeLightning />

    <div id="AccountSummaryAppDiv"/>

    <script>
        $Lightning.use("c:AccountSummaryApp", function() {
            $Lightning.createComponent("c:AccountSummaryComp"
                , {"recordId" : "{!accountId}", "numrows" : "{!numrows}"}
                , "AccountSummaryAppDiv"
                , function(cmp) {
                    console.log('[Account360Page] Printable Account 360 initialized');
                });
            });
    </script>

</apex:page>

The button to launch the Visualforce page in a separate tab, consists of nothing more than this.

printPageAction: function(component, event, helper) {
	var url = location.origin + '/apex/Account360Page?id=' + component.get("v.recordId");
	window.open(url, '_blank');
}

Bringing up the Print dialog is a one-liner.

printAction: function(component, event, helper) {
	window.print();
}

And to be honest, I was pretty surprised how well the end-result looked in printed form. I did take some small additional measures, most important one to set the number of lines the CMTD Enhanced Related List components would display to be maximum 50. That is, without the user having to click ‘Show more’ before hitting the ‘Print’ button.

print360sr.gif

Summarizing, Visualforce + Lightning is a happy marriage if you’re looking to print it.

Lightning Refresh Component, No More F5!

Probable the most lightweight Lightning component I ever did, but that doesn’t necessarily mean it isn’t useful. It actually can turn out utterly useful, preventing F5 or Cmd+R to refresh cached Lightning record pages. And yeah, from time to time you’re looking at stale data, and forcing Salesforce to retrieve new data shouldn’t be done using before-mentioned methods. It creates a terrible user experience, forcing the user to look again at the release image for some seconds in order for Salesforce to complete reloading.

Instead a simple component with a single like of declarative code, and a single line of controller code which can be used in your record pages. It refreshes the right way.

Simply put in on your page using the page builder.

refresh1

refresh2

Install it to your org right away?

Deploy to Salesforce

Or check the Git.

Force.com REST API Explorer – New kid on the block

fcrestapi

Till date experimenting with a Salesforce API has always been most efficient using the Workbench’s REST Explorer. Workbench is a powerful tool of many trades, and a very well maintained open source project at the same time. And navigating REST resources is a key feature. Almost celebrating its 10th anniversary after its conception in 2008 by Ryan Brainard (and today Ryan is a member of Heroku’s technical staff, he made it possible to deploy your own private Workbench app on the Heroku platform). Enough on Workbench.

Because there’s a new kid on the block – the Force.com REST API Explorer or ‘Force.com REST API sObject Resources’. Today in the form of a Developer Review. In its current form, it’s essentially adding documentation to sObject API resources. And at the same time providing an option to try ‘m out.

fcrapi1

In its current form, the added resource documentation is probable the big differentiator. But actually invoking and testing a REST service is – well – as cumbersome as it it using Workbench, Postman or similar. You have to still manually craft your body, because the explorer only provides boilerplate JSON.

rae_body

Of course you could first fetch a record by its ID (Find <sObject> by ID) and next copy & paste that into an update or insert body, modify some data and invoke it. And since the returned REST URLs are not navigable (they aren’t hyperlinked) as you’re used to with Workbench or Postman, that’s not helping much either. So at this point, I guess it’s primarily useful as documentation tool around Salesforce objects. That said, it’s a developer preview and hopefully has a great future and roadmap. For example, wouldn’t it be great to more easily be able to mock-up request bodies with sample data available in the org without having to go through copy & paste exercises?

Other than that, the API version today is fixed to 39 (which is Spring ’17) where the current release is Winter ’18 (41). So new objects, or new fields or relationships on existing objects won’t be up to par with the current release. Performance of navigating the REST API Explorer isn’t good at this moment, probable because it’s still a developer preview. Looking a bit deeper, it appears that the page uses the Turbo-Links library, but effectively disables caching. That makes the page to reload all libraries (JQuery, SFLDS, …) when switching between resources all the time.

turbolinks

nocache-turbolinks

Recaptcha vs. Lightning

This happens to be my very first Cloudm@tters post. The title shouldn’t be too misleading, it’s all about Google’s Recaptcha and Salesforce Lightning. More specifically Lighting Communities. The Salesforce Winter ’18 release brought us “Communities in Enterprise, Performance, and Unlimited Editions – Even Without Communities Licenses“. A great benefit, because any customer on an Enterprise, Performance or Unlimited plan can leverage a public facing community, included in their licenses. With that remark, that page views are limited to 500,000 for Enterprise and 1,000,000 for Unlimited. And you get the full-featured capabilities of Lightning Templates and Community Builder.

While working on a VTO engagement, to deliver a pretty straight-forward landing page for fundraising – I opted for this new Winter ’18 feature. The non-profit is benefitting through their  Salesforce.org membership, from this feature because through Salesforce.org an eligible non-profit owns 10 Sales Cloud Enterprise Edition licenses.

I was looking for something like below, where using a public community we’d protect using Recaptcha the first step of creating a donation, that is providing a set of credentials. Clicking the Recaptcha would – if successful – pass this first step.

recpatchacomm

After successfully passing the Recaptcha check…

recapsuccess

Creating a Lightning Customer Service Napili-based community these days is a matter of just a few clicks. Which is great, because you get a descent looking landing page without any hassle. And instead of having to deal with traditional Web-to-lead once could immediately create the record in a Salesforce object. But being a public and open-to-all landing page, the intrinsic risk of bot abuse is apparent. To safeguard for that, Recaptcha is the default tool of choice these days.

Recaptcha provides a really simple API. But that same API has one very big caveat. It’s a dynamic library, hence cannot be hosted as static resource on the Salesforce platform. If you’d load the library, this is what you’d get. And you’ll be immediately informed about the correct use…

/* PLEASE DO NOT COPY AND PASTE THIS CODE. */
(function () {
    if (!window['___grecaptcha_cfg']) {
        window['___grecaptcha_cfg'] = {};
    };
    if (!window['___grecaptcha_cfg']['render']) {
        window['___grecaptcha_cfg']['render'] = 'onload';
    };
    window['__google_recaptcha_client'] = true;
    var po = document.createElement('script');
    po.type = 'text/javascript';
    po.async = true;
    po.src = 'https://www.gstatic.com/recaptcha/api2/r20171115120512/recaptcha__nl.js';
    var elem = document.querySelector('script[nonce]');
    var nonce = elem && (elem['nonce'] || elem.getAttribute('nonce'));
    if (nonce) {
        po.setAttribute('nonce', nonce);
    }
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(po, s);
})();

Because the library is dynamic, and it cannot serve as a static resource – using the library within a Lightning Component isn’t possible. At least not through the traditional route to embed 3rd-party libraries.

However, embedding Recaptcha within a Visualforce page, is a more traditional means. Has been done often enough, and it’s documented. A Visualforce page can be easily exposes as part of a Lightning component by means of including an iframe source. Not ideal, by any means because it breaks the default Lightning app & component communication pattern. Default you’d either use composition or lightning events. But working with an iframe, you’re bound to using more old-school (or should I say traditional) means: using postMessage. Salesforce has a quality reading on this topic, so I don’t need to write it again. The essence is that an iframe owns it own DOM, as it where a browser-in-a-browser.

The good thing of Visualforce pages is, that is allows embedding in a more traditional way 3rd-party libraries. And that method has been proven for many years. So let’s start with that Visualforce page then.

<apex:page controller="reCAPTCHA">
    
    <!-- Styling to eliminate border on the iFramed content --> 
    <style type="text/css">
        .bPageBlock.brandSecondaryBrd.apexDefaultPageBlock.secondaryPalette {
            border: none; 
        }
    </style>
    
    <apex:pageBlock >
        <apex:form >
            <!-- recaptcha placeholder element -->
            <div id='recaptcha'/>
               
            <script type="text/javascript">
                var captchaSuccess = function() { 
                    var origin = location.origin;
                    parent.postMessage('success', origin);
                };
                
                var repatchaReady = function() {
                    grecaptcha.render('recaptcha', {
                        'sitekey' : '{!publicKey}'
                        , 'callback': captchaSuccess
                    });
                };
            </script>    
            
            <!-- The Google reCaptcha API loads first with a callback -->
            <script src="{!apiEndpoint}?onload=repatchaReady&render=explicit"/>

    </apex:form>
  </apex:pageBlock>
</apex:page>

Loading the Recaptcha library following Google’s advice, provides a callback. You only nee to pass in the ‘site key’ which you get after registering with Google (which is a completely free service, I forgot to mention). The code snippet should be pretty much self-explanatory. Beware that I use custom settings, to cater for a generic and re-usable solution. And the piece of embedded CSS (typically a no-go) is simply to get rid of the colored like around the iframe (that colored line is nasty, and cannot be suppressed differently I found). Oh yeah, thing to mention about XSS. To cater for same-origin, make sure you pass in the origin when posting to the parent.

The controller is simple, nothing fancy. Just getting the necessary custom settings.

public class reCAPTCHA {

    public static String apiEndpoint {
        get { return ( getCustomSetting('ApiEndpoint__c')); }
    }

    public static String publicKey {
        get { return ( getCustomSetting('PublicKey__c')); }
    }

    private static String getCustomSetting(String customSetting) {
        try {
            return ( String.valueof( GoogleRecaptcha__c.getValues('Recaptcha').get(customSetting) ) );
        }
        catch (Exception e) {
            system.debug('[Recaptcha Exception] it seems the Recaptcha Custom Settings are not available:' + e.getMessage());
            return ('NOK');
        }
    }
}<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

The Visualforce page itself should be made public as well, so it will live in the same domain as the community. That actually tackles the same-origin problem already. To make your Visualforce page publicly accessible, you need to go through a number of steps:

  • Setup > All Communities > Workspaces (wait to have it load)
  • Click on the “Communities Workspaces” tile in the top left-hand corner
  • Click “Administration” then click on “Go to Force.com”

ac

  • You’ll see that “Clickjack Protection Level” is set to “Allow framing by the same origin only”. On the top click on “Public Access Settings”, then click “Visualforce Page Access”
  • Click “Edit” to add the Visualforce page hosting the Recaptcha libary, and save.

That done, it’s time to scaffold the Lightning component itself. Since goal is to create a reusable component (remember, Lightning is all about Composition) I start of with a the component which just hold the Visualforce page and handles the communication.


    
    
    
	

The component’s controller (yes, it ain’t much):

({
	init: function(component, event) {
		window.addEventListener("message", function(event) {
			component.getEvent("reCaptchaSuccessEvt").fire();
        }, false);
	}
})

Really? Yep. Really. To communicate with the component’s parent, an event is fired of “reCaptchaSuccessEvt”. That event may or may not be handled upstream. That’s the beauty of loose coupled events.

Now, the Lightning component which takes it’s hasn’t a lot to do.

<aura:component implements="forceCommunity:availableForAllPageTypes" controller="KCS_LoginController">
	
    <aura:attribute name="loginResult" type="Boolean" default="false"/>
    <aura:attribute name="initialLogin" type="Boolean" default="true"/>
    <aura:attribute name="emailProfile" type="String"/>
    <aura:attribute name="nameProfile" type="String"/>
    <aura:attribute name="urlReCaptchaVF" type="string"/>
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>
    <!-- registering event handler -->
    <aura:handler name="reCaptchaSuccessEvt" event="c:reCaptchaSuccessEvt" action="{!c.handleLogin}"/>

	<aura:if isTrue="{!!v.loginResult}">
        <lightning:card title="Inloggen">
            
           <!-- <aura:set attribute="actions">
                <lightning:button variant="brand" label="Inloggen" onclick="{!c.handleLogin}"/>
            </aura:set> -->
        
            <lightning:layout >
                <lightning:layoutItem padding="around-small">
                    <lightning:input aura:id="email" variant="brand" type="email" label="Email" name="email" placeholder="Vul hier jouw emailadres in" />
                </lightning:layoutItem>
                <lightning:layoutItem padding="around-small">
                    <lightning:input aura:id="pin" type="password" label="Pincode" name="pin" placeholder="5 cijfers van jouw pincode" minLength="5" maxLength="5"/>
                </lightning:layoutItem>
            </lightning:layout>
            
            <!-- passing in both the Visual force page hosting the reCaptcha and the originating host url -->
            <c:reCaptchaLightning urlReCaptchaVF="{!v.urlReCaptchaVF}"/>
            
        </lightning:card>
    </aura:if>
    <aura:if isTrue="{!v.loginResult}">
		<lightning:tile label="Welkom!">
			<aura:set attribute="media">
				<lightning:avatar src="https://pbs.twimg.com/media/CtUdvL3UEAAZZrp.jpg" class="slds-avatar_circle slds-avatar_large" alternativeText="Astro"/>
			</aura:set>

            <dl class="slds-dl--horizontal">
				<dt class="slds-dl--horizontal__label">
					<p class="slds-truncate" title="Company">Ik ben:</p>
				</dt>
				<dd class="slds-dl--horizontal__detail slds-tile__meta">
					<p class="slds-truncate" title="Salesforce">{!v.nameProfile}</p>
				</dd>
				<dt class="slds-dl--horizontal__label">
					<p class="slds-truncate" title="Email">Email:</p>
				</dt>
				<dd class="slds-dl--horizontal__detail slds-tile__meta">
					<p class="slds-truncate" title="salesforce-ux@salesforce.com">{!v.emailProfile}</p>
				</dd>
			</dl>
		</lightning:tile>
    </aura:if>
    
</aura:component>

And a few lines of support Apex controller code, to get the site prefix.

public class KCS_LoginController {
    @AuraEnabled
	public static String getCommunityUrlPrefix () {
		return [SELECT UrlPathPrefix FROM Network WHERE Id = :Network.getNetworkId()].UrlPathPrefix;
	}
}

Create the few neccesary custom settings, don’t forget about that. Plugged all together, and you have a beautiful Lightning-enabled safeguard for bots. Enjoy!

PS: Will put stuff on Git soon.