I don’t work that much with Lotus Notes and Domino or Sametime anymore but I have been using it though. The other day I discovered by mistake two handy keyboard shortcuts.
Development
On an account under ‘Activity History’ you have the option to:
- Log a Call
- Mail Merge
- Send An Email
- Go to Administration Setup -> Email Administration -> Organization-Wide Addresses
- See the listed sitewide email addresses.
- Click edit on anyone to modify or create a new.
- In edit mode you can choose which profile has the right to use the address. A user with a specified profile can see this address in the from address field in the Send an Email window.
When people are leaving a company, they are sometimes still in the org which causes some problems. They could be listed in different settings but also as running users of dashboards. Here is a good way of listing the dashboards where a specific user is set as the running user.
- Create a custom report type with Dashboard as the primary object
- Create a report with this report type
- Make it two columns; Title and Running User: Full Name
- Add a filter: Dashboard Running Users equals “Run as specified user”
- Save and run report and click on the name column to sort
This is something that should be added to a routine when someone leaves the company and not only for sudden problems.
If you get this error while working with a Visualforce page in Salesforce the reason could be that you are trying to call a method that doesn’t exists in the action attribute of the apex:page tag. I.e. in this case ‘aMethod’ does not exist in class ‘controllerClass’.
<apex:page title="A Title" standardController="Opportunity"
extensions="controllerClass" tabStyle="Opportunity" showheader="true"
sidebar="true" action="{!aMethod}" >
Here is an example of
1) how to query fields of an object and fields on records of a related object
2) how to loop over the queried records and the records of the related object in Apex
In the below example the Opportunity is the master of a master-detail relationship where Sub_Object__c is the detail. The task is to query fields and set these to values on both the opportunity and to the related Sub_Object__c records.
public void resetStates() {
// Create map of a list of opportunities.
Map theMap = getTheMap();
// List all opportunities except the selected one,
// i.e. the map excludes the selected opp.
List allOpps = [SELECT Id, Selected__c,
(SELECT id, Selected__c FROM Sub_Object__r) FROM Opportunity
WHERE Id IN: theMap.keySet()];
// Loop over the opportunities and set values
for (Opportunity o : allOpps) {
o.Selected__c = false;
// Loop over the records retrieved in the nested SELECT statement and set values
// Do this for each opportunity
for (Sub_Object__c so : o.Sub_Object__r) {
so.Selected__c = false;
}
}
// Update the db with the new values
update allOpps;
}
When you are working with profiles and access rights in a Salesforce organization or when you are developing new functionality or modifying existing, you will sooner or later need to modify the profiles.
Example:
Assume you have created new functionality which includes a new custom object. You will need to give the profiles access to this new object.
If you have a large organization there could be quite a lot of profiles. So start by creating a profile view that lists the profile settings that you want to modify. See this post for more info on how to do that.
So let’s look at the same screen shot as in the referred post.
Let’s say want to modify the delete access for all custom profiles
1. Start by selecting the check boxes for the custom profiles.
2. Then double-click in the column “Opportunity: Delete” in any of the selected rows.
3. You will see this screen

The check box “Opportunity: Delete” is unchecked since this is what we want to do. In the middle you see what this change means, i.e. settings that will be disabled as a consequence.
At the bottom you can choose to perform the action for the row that you clicked on only or check “All 3 selected records” to perform the action on all custom profiles.
You will be redirected back to the profile view and can instantly see that the custom profiles have lost their delete access to the Opportunity object.
I have written about this before, but I think this is more detailed and easier to read.
It happens quite often both as an admin and as a developer that you need to check profile access. One way to do this is to open each profile one at a time to check for for example each profile’s access to a specific object. This could be a quite tiresome work especially if you have a large and complex org with many profiles.
At these times I always create a profile view which gives me a view of exactly what I want to see all at once. And its very simple to do too.
So here’s how to do it:
1. First make sure that you can create profile list views. Goto Administration Setup -> Customize -> User Interface. The checkbox ‘Enable Enhanced Profile List Views’ should be checked.
2. Open up the User Profiles view (Administration Setup -> Manage Users -> Profiles). All profiles are listed here and you can see the default view ‘All Profiles’.
3. Now, if you want to see the profile’s access rights for the opportunity object for example you start by creating a new view. Click ‘Create New View’.
4. Name the view something, e.g. ‘Opportunity Access’.
5. Filters can be added, this is optional though. But assume you have a lot of custom profiles that are prefixed with “MyCompany: “. If I only want to see them I can add the filter with Setting “Profile Name” starts with “MyCompany: “.
6. In step 3 you specify what you want to see in the view. In this case add:
Opportunity: Read
Opportunity: Create
Opportunity: Edit
Opportunity: Delete
7. Now choose the new view ‘Opportunity Access’ in the select list of the profile page. As you can see you get a good overview and can make further decisions based on this.
On a visualforce page I want to display notes from an opportunity. To accomplish this I need a VF-page and an extension class (apex).
Part of VF-page that displays the notes:
<apex:outputPanel>
<apex:pageBlock title="Notes" mode="maindetail">
<apex:pageBlockTable value="{!MainOppNotes}" var="n">
<apex:column headerValue="Action" width="5%">
<apex:commandLink action="{!viewNote}" id="viewNote"
value="View" styleClass="actionLink">
<apex:param name="noteId" assignTo="{!noteId}" value="{!n.Id}" />
</apex:commandLink>
</apex:column>
<apex:column headerValue="Name" width="65%">{!n.Title}</apex:column>
<apex:column headerValue="Last Modified" width="30%">
<apex:outputtext value="{!n.LastModifiedByName}" />,
<apex:outputtext value="{!n.LastModifiedDateStr}" />
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:outputPanel>
The getMainOppNotes method from the extension class:
// Get notes from the main opportunity.
public List<RetObject> getMainOppNotes() {
List<RetObject> rtObjs = new List<RetObject>();
RetObject rt = new RetObject();
List<Note> mainOppNotes =
[select Id, Title, LastModifiedDate, LastModifiedById
from Note where ParentId = :mainOppId];
for (Note n : mainOppNotes) {
rt = new RetObject();
rt.Id = n.Id;
rt.Title = n.Title;
rt.LastModifiedDate = n.LastModifiedDate;
rt.LastModifiedByName = userMap.get(n.LastModifiedById);
rtObjs.add(rt);
}
rt = null;
return rtObjs;
}
In the method above there is first a SOQL-query to get all notes for a specific opportunity. I want to return Id, Title, LastModifiedDate and LastModifiedBy name for the Note. Since Note has a field LastModifiedById we can only get the id which is not very readable.
A solution to this is to create an wrapper class to the extension class which can be used as an internal object that can hold all the values I wan’t to return to the VF-page. In this case it is called RetObject.
For each Note an instance of RetObject is created and put in a list of the RetObject type. The method is set to return a list of this type and that is what is done when the looping has finished.
The RetObject type contains 4 fields. One is the LastModifiedByName. All fields except this field get their values from a Note. The LastModifiedByName field gets its value from the user map. The usermap consists of a map of type String and Id and contains all active users in the org. This way we can do a quick lookup using the LastModifiedById from the Note.
The user map is created in the constructor and is defined as a private class attribute:
// Create user map
List<User> users = [select id,name from User where isActive = true];
userMap = new Map<ID, String>();
for (User u : users) {
userMap.put(u.id, u.name);
}
The wrapper class looks like this:
// Wrapper class. Used to return a set of information to
// display to the user on the VF-page
public class RetObject {
public RetObject() {}
public ID Id {get; set;}
public String Name {get; set;}
public String Title{get; set; }
public Datetime LastModifieddate {get; set; }
public String LastModifiedDateStr {get {
return LastModifieddate.format('yyyy-MM-dd hh:mm');
} set; }
public String LastModifiedByName {get; set;}
}
In the former post I briefly described the Cloud-Based Flow Designer. In this article I will show how to create a simple flow using the Cloud-Based Flow Designer in Salesforce with Apex plug-ins. The plug-in will take a name from the user and display it back backwards.
- Start by creating a flow (App Setup -> Create -> Workflow & Approvals -> Flows).
- You can see all your flows in this list. Press ‘New Flow’. If you already have one, press ‘Open’.
- Drag a screen element from the Palette to the canvas.
- Name it (Get Name).
- Add a field (Name, textbox).
- Set it as the start element in the flow. Click the arrow in the upper right corner so that it becomes green.
- Drag a screen element from the Palette to the canvas.
- Name it (Result).
- Click on ‘Display Text’ on the ‘Add a Field’ tab. This is the output text field of the screen. Note the name of this field. Mine is named ‘NameBackwardsResult’.
- As the output, select ‘SCREEN INPUT FIELDS’ as resource and choose the already defined ‘Name’ field.
- It should now say ‘{!Name} backwards is’.
- We will come back to this one a bit later.
- Save flow.
We need to use some Apex now to do the actual work of creating the name input string backwards. For this you need to use Eclipse and the Force.com IDE. I assume you have knowledge of this.
The invoke method does the actual work. It gets the input parameters, does some calculations and return something.
Once this class has been created this way it will be visible in the Palette tab of the Flow Designer . The tag defined in the describe method is the name of the section and the name defined is the name of the actual plugin. See ‘Name Backwards’ and ‘nameBackwardsPlugin’ in the screenshot below.
global class FlowTest implements Process.Plugin {
// Invoke method
global Process.PluginResult invoke(Process.PluginRequest request) {
String name = (String) request.inputParameters.get('name');
String nameBackwards = '';
try {
String[] nameList = new String[name.length()];
Integer counter = 0;
for (Integer i=name.length()-1; i>=0; i--) {
nameList[counter] = name.substring(i, i+1);
counter++;
}
for (Integer j=0; j<=nameList.size(); j++) {
nameBackwards+=nameList[j];
}
} catch (Exception e) {
System.debug(e);
}
Map<String,Object> result = new Map<String,Object>();
// Add value to output parameter and return.
result.put('result', nameBackwards);
return new Process.PluginResult(result);
}
// Describe method. Returns the describe information for the interface
global Process.PluginDescribeResult describe() {
Process.PluginDescribeResult result = new Process.PluginDescribeResult();
result.Name = 'nameBackwardsPlugin';
result.Tag = 'Name Backwards';
result.inputParameters = new
List<Process.PluginDescribeResult.InputParameter> {
new Process.PluginDescribeResult.InputParameter('name',
Process.PluginDescribeResult.ParameterType.STRING, true)
};
result.outputParameters =
new List<Process.PluginDescribeResult.OutputParameter> {
new Process.PluginDescribeResult.OutputParameter('result',
Process.PluginDescribeResult.ParameterType.STRING)
};
return result;
}
}
You can have several input- and output arguments. Just define any extra input- and output parameters to the inputParameter and outputParameter lists in the describe method. Create new strings to get extra input parameters in the invoke method and add more key-values in the map for the output parameters in the invoke method.
Add plug-in to flow
Open up the flow again. If it was already open you probably need to refresh it or close and open it again.
Now click the Resources tab and double-click on variables. You are going to create a variable that will be assigned the output value of the plugin. My is named ‘NameBackwards’ and is of type text.
In the Palette you should now see the plugin as described in the screenshot above. Drag the nameBackwardsPlugin to the canvas. Mine is named ‘Calculate Name Backwards’. You will have to define inputs and outputs to the plugin corresponding to what you have just coded in the Apex plugin. So in this case the input would be the screen input field ‘Name’ and the output would be the variable ‘NameBackwards’ you just created.
Back to the end screen
Open up the end screen by double clicking it and go to the ‘Field Settings’ tab. Select resources and variables and ‘NameBackwards’ and add to the end of the output string. It should now read ‘{!Name} backwards is {!NameBackwards}!’.
See the Resources tab to see what we have created so far.
Finish the flow
Just add connectors between the elements and you’re done. Click a diamond for an element, hold the mouse button down and release it when you are in a receiving elements diamond.
The flow is done. Save and Run to test it. You can also put the flow in a Visualforce page. This would be the code for doing that. ‘Play_with_Name’ below is the name of the flow.
<apex:page> <h1>Your name backwards!</h1> <flow:interview name="Play_with_Name"></flow:interview> </apex:page>
Running the flow
Opening the new Visualforce page and running the flow will result in these screens.
Good Luck!
With the Winter ’12 release of Salesforce comes the new Cloud-Based Flow Designer (as a beta). It works with production quality but has some limitations. You can find it under Workflow & Approval in the Administration Setup.
A visual workflow allows administrators to set up collections of screens, or flows, that step users through the process of collecting and updating data. Simple flows can easily be setup. Elements are dragged onto a canvas from a left pane. For example screens to the user to get input, logic like decision handling and ways to get, create and update underlying Salesforce data.
Sometimes there might be a need for more complex calculations and in these cases Apex functionality can be used. Special Apex classes are then created and can be used as plugins to the flows with in- and out parameters. The next blog post will cover an example of this.
Furthermore created flows can be added to Visualforce pages. Hence, this is a very good tool for administrators, sometimes in cooperation with developers, to create useful and complex flows to provide a very good solution to their customers and users.
| Limits of a flow: | ||
| Maximum number of versions per flow | 10 | |
| Maximum number of steps per flow | 2000 | |
| Maximum number of active flows per organization | 500 | |
| Maximum number of flows per organization | 1000 | |
| Maximum size of uploaded flow file | 3MB | |
The differences from the already existing Desktop-Based Flow Designer version can be found here. Download the latest version of the desktop version here.
See a demo of the Cloud-Based Flow Designer here.





























