lekkimworld.comA blog by Mikkel Flindt Heisterberg about everything and nothing - mostly appdev stuff...tag:lekkimworld.com,0000-00-00:defaultMikkel Flindt Heisterberg2017-08-11T15:06:53ZMikkel Flindt Heisterberg2017-08-11T15:06:53ZenMikkel Flindt HeisterbergThe best way to learn a platform is to use a platformMikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-08-11:default/15024640136842017-08-11T19:27:19Z2017-08-11T15:06:53Z<p>
Wow what a week it's been. First week back from vacation and I'm diving right into a sprint of stuff that needs to be delivered to the customer. My task for the week has been develop a connectivity layer between Salesforce and <a href="https://www.dropbox.com">Dropbox</a> using OAuth. This task has taken me on quite a learning journey.
</p>
<p>
Now I'll call myself quite a seasoned programmer but ever since joining Salesforce 9 months ago I've had to relearn a lot of stuff. A new programming language in Apex, new framework technologies such as Salesforce Lightning Design System (SLDS) and the Lightning Platform and the entire underlying Salesforce Platform which is enormous. There are just different ways to do stuff... Previously I would have had my choice of any language, technology and framework to solve the issue but now those are kind of given.
</p>
<p>
Just this afternoon as I was putting the final semi-colons in the core OAuth layer (Apex), the Dropbox specific OAuth layer (Apex), the business specific facade class in front of those layers (Apex) and the management pages for the integration (Lightning) I was reminded of an old quote from an old biochemistry text book of mine: "The best way to learn a subject is the teach the subject". And that continues to hold true and is equally true when saying "the best way to learn a platform is to build on the platform". I've learned much stuff about Apex and Lightning in the past week. All the cool stuff you can do but also some of the crazy stuff that falls into that "you have have to know that"-category. But for all those things it holds true that you have to spend the time to reap the benefits.
</p>
<p>
For now I'll just say that although the Apex language has it quirks and the compiler is definitely showing age (and Salesforce knows this - a new compiler is being developed or at least that's what I heard in a Dreamforce 2016 session) there is still much so much power in the language. Is there stuff you cannot do? Sure! But there are cool interfaces like <a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_interface_System_StubProvider.htm">System.StubProvider</a> which I read and hear little talk about. The built in support to unit tests and mocking of HTTP requests is awesome and allows you to quickly and easily stub out calls to external services. The runtime screams with performance and I'm pretty impressed about the speed with which my code runs.
</p>
<p>
Good stuff!
</p>
<p>
So in closing - I have my OAuth layer done, unit tested and commited. I'll surely be blogging about how to chose to build it so others may learn from it if they want to spend the time and learn the platform.
</p>2017-08-11T15:06:53ZFlip Chrome flag to easily inspect TLS certificates (from Chrome 60)Mikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-08-08:default/15021862250572017-08-08T09:57:05Z2017-08-08T09:57:05Z<p>
As a developer - or a security conscious user - you may want to inspect TLS certificates from time to time. However inspecting them in Chrome is hard as access to the certificate hierarchy dialog has been tucked away in the Developer Tools. Happily Chrome 60 has added a flag to add an easy to reach option back to the TLS dropdown in Chrome.
</p>
<p>
<b>Please note that manually editing Chrome browser flags may mess up your browser - don't say I didn't warn you...</b>
</p>
<p>
In the below video I show you how...
</p>
<p align="center">
<iframe width="560" height="315" src="https://www.youtube.com/embed/9WSGtAlimVE" frameborder="0" allowfullscreen></iframe>
</p>2017-08-08T09:57:05ZDeveloping Salesforce Lightning Components that are visible at design time but not at runtimeMikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-06-29:default/14987657069362017-06-29T19:48:26Z2017-06-29T19:48:26Z<p>
So this can clearly be labelled as a "Lightning Lesson from the Field". As you start to develop more complicated Salesforce Lightning applications - and why wouldn't you - you as I have done start seeing great power in hidden components. By hidden components I mean components that contribute code or does "something" but which does not have a UI. Thes are very easy to do but have a big drawback as they are also invisible at design time making them near impossible to find the Lightning AppBuilder. To work around this I've come up with a hack that has proven itself very useful.
</p>
<p>
By using a combination of two simple attributes and 3 lines of JavaScript I can make the component markup visible at design time but invisible at runtime. Or if I need to toggle it on for runtime as well using an attribute I can set from the Lightning AppBuilder.
</p>
<p>
The video below goes more in depth and illustrates the concept. Happy coding.
</p>
<p align="center">
<iframe width="560" height="315" src="https://www.youtube.com/embed/tvTKxxYzj_w?list=PLz8RqWXvEsBpEfduGIcZ3Kg2Nc5Rbt4PU" frameborder="0" allowfullscreen></iframe>
</p>2017-06-29T19:48:26ZDeploy your own Salesforce Workbench on Heroku at the click of a buttonMikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-06-22:default/14981188408172017-06-22T08:07:20Z2017-06-22T08:07:20Z<p>
The other day <a href="http://workbench.salesforce.com">Salesforce Workbench</a> 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 <a href="http://www.heroku.com">Heroku</a> 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):
<ol>
<li>Go to the project page at <a href="https://elements.heroku.com/buttons/jdrishe/salesforce-workbench">https://elements.heroku.com/buttons/jdrishe/salesforce-workbench</a></li>
<li>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)</li>
<li>Log into the deployed app (remember to add your security token after the password but I guess you knew that!!) and you are done!</li>
</ol>
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!!
</p>
<p align="center">
<iframe width="560" height="315" src="https://www.youtube.com/embed/ibUXgd-nr7I" frameborder="0" allowfullscreen></iframe>
</p>2017-06-22T08:07:20ZCurrency conversion in ApexMikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-06-20:default/14979849792132017-08-09T19:03:25Z2017-06-20T18:56:19Z<p>
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.
</p>
<p>
Please note code is provided as-is without any warrenties or guarantees. As a friend always writes --- <a href="http://www.urbandictionary.com/define.php?term=ymmv">YMMV</a>....
<pre>
public class CurrencyConverter {
private Map<String, CurrencyType> 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<String, CurrencyType>();
final List<CurrencyType> 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<User> 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 {
}
}
</pre>
</p>2017-06-20T18:56:19ZSimplifying usage of Salesforce Lightning Design System using NPM and ExpressMikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-06-14:default/14974437755272017-06-14T12:36:15Z2017-06-14T12:36:15Z<p>
Using <a href="https://www.lightningdesignsystem.com/">Salesforce Lightning Design System</a> (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.
</p>
<p>
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.
</p>
<p>
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:
<pre>
const app = express();
app.use('/slds', express.static(__dirname + '/node_modules/@salesforce-ux/design-system/assets'));
</pre>
Then loading SLDS assets into my app is as easy as:
<pre>
&lt;link rel="stylesheet" type="text/css" href="/slds/styles/salesforce-lightning-design-system.css" /&gt;
</pre>
</p>
<p>
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.
</p>2017-06-14T12:36:15ZSalesforce week 25-27 and finishing this weekly thing...Mikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-05-22:default/14954351234722017-05-22T06:38:43Z2017-05-22T06:38:43Z<p>
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.
</p>
<p>
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.
</p>
<p>
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.
</p>
<h3>Top 5 from my first 6 months</h3>
<ul>
<li>Develop on the new Salesforce Lightning and become quite good at it</li>
<li>"Master" Salesforce and become 5 times Salesforce certified</li>
<li>Bootcamp in San Francisco</li>
<li>Delivering real business value at my customer and doing it with Lightning</li>
<li>Working with very nice and talented people</li>
</ul>
<h3>Status after this week</h3>
<p>
Trailhead points: 85325
<br/>
Trailhead badges: 100
<br/>
Certifications: 5 (Salesforce Certified Administrator, Salesforce Certified Platform App Builder, Salesforce Certified Advanced Administrator, Salesforce Certified Sales Cloud Consultant, Salesforce Certified Service Cloud Consultant)
</p>2017-05-22T06:38:43ZSalesforce Lightning Component API changeMikkel Flindt Heisterberghttp://lekkimworld.com/abouttag:lekkimworld.com,2017-05-17:default/14950109582742017-05-25T08:30:21Z2017-05-17T08:49:18Z<p>
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:
<pre>
({
react: function(component, event, helper) {
const elem = event.getSource().getElement();
}
})
</pre>
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...
</p>2017-05-17T08:49:18Z