Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jeff Douglas
committed
Jul 20, 2011
0 parents
commit 482358f
Showing
21 changed files
with
519 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Salesforce.com Org Chart | ||
|
||
URL: http://www.cloudspokes.com/challenge_detail.html?contestID=152 | ||
Blog: http://blog.cloudspokes.com/2011/04/salesforcecom-org-chart-winner.html | ||
Challenge end date: Mon Apr 04 05:00:00 GMT 2011 | ||
|
||
Description | ||
=========== | ||
We'd like to create a Visualforce page that displays an Org Chart for Salesforce.com users. The chart should be displayed using the Google Visualization API. | ||
|
||
Requirements | ||
============ | ||
Using a Developer org, create a Visualforce page and Apex controller that displays an Org Chart for the current active users. Displaying titles is optional but it would be nice. Ideally, place the business logic for the Org Chart creation in a separate Apex class that is called by the controller. |
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Copyright (c) 2011 CloudSpokes | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<defaultLandingTab>standard-home</defaultLandingTab> | ||
<label>Org Chart</label> | ||
<tab>standard-Chatter</tab> | ||
<tab>Org_Chart</tab> | ||
</CustomApplication> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/** | ||
* @author KevinSwiggum | ||
* Copyright 2011 Radial Web Solutions LLC | ||
*/ | ||
public with sharing class OrgChart { | ||
|
||
static Boolean chatterEnabled = true; | ||
|
||
/** | ||
* populates a list of RoleWithUsers object for the given selectedRoleIds | ||
* @author KevinSwiggum | ||
*/ | ||
public static List<RoleWithUsers> getRolesWithUsers(Set<ID> roleIds) { | ||
List<RoleWithUsers> rolesWithUsersList = new List<RoleWithUsers>(); | ||
List<UserRole> roles = new List<UserRole>(); | ||
try { | ||
roles = [SELECT ID | ||
, Name | ||
, ParentRoleId | ||
, (SELECT ID, name, title, email, phone, SmallPhotoUrl FROM Users WHERE IsActive=true) | ||
FROM UserRole | ||
WHERE parentRoleId IN :roleIds | ||
OR ID IN :roleIds | ||
ORDER BY ParentRoleId NULLS FIRST, ID]; | ||
} catch (System.Requiredfeaturemissingexception e) { | ||
//catches an error in the event that chatter is not enabled in this org. | ||
roles = [SELECT ID | ||
, Name | ||
, ParentRoleId | ||
, (SELECT ID, name, title, email, phone FROM Users WHERE IsActive=true) | ||
FROM UserRole | ||
WHERE parentRoleId IN :roleIds | ||
OR ID IN :roleIds | ||
ORDER BY ParentRoleId NULLS FIRST, ID]; | ||
chatterEnabled = false; | ||
} | ||
//Populate the list | ||
rolesWithUsersList = new List<RoleWithUsers>(); | ||
for (UserRole ur : roles) { | ||
rolesWithUsersList.add(new RoleWithUsers(ur, (roleIds.contains(ur.id)))); | ||
} | ||
|
||
return rolesWithUsersList; | ||
} | ||
|
||
public static Set<ID> getTopUserRoleIds() { | ||
Set<Id> roleIds = new Set<Id>(); | ||
List<UserRole> topRoles = [SELECT ID FROM UserRole WHERE parentRoleId = null]; | ||
for (UserRole ur : topRoles) { | ||
roleIds.add(ur.ID); | ||
} | ||
return roleIds; | ||
} | ||
|
||
public static Set<ID> getAllRoleIds() { | ||
Set<Id> roleIds = new Set<ID>(); | ||
List<UserRole> topRoles = [SELECT ID FROM UserRole LIMIT 500]; | ||
for (UserRole ur : topRoles) { | ||
roleIds.add(ur.ID); | ||
} | ||
return roleIds; | ||
} | ||
|
||
/** | ||
* Inner class that holds the UserRole (with the Users related list already populated). | ||
* Provides helper methods for formatting output text | ||
* @author KevinSwiggum | ||
*/ | ||
public class RoleWithUsers { | ||
public UserRole role {get; set;} | ||
public Boolean isExpanded {get; set;} | ||
|
||
/** | ||
* Contructor. Expanded tells the class if this role has been clicked on and expanded | ||
* @author KevinSwiggum | ||
*/ | ||
public RoleWithUsers(UserRole rl, Boolean expanded) { | ||
this.role = rl; | ||
this.isExpanded = expanded; | ||
} | ||
|
||
/** | ||
* returns the UserRoleId | ||
* @author KevinSwiggum | ||
*/ | ||
public String getId() { | ||
return role.id; | ||
} | ||
|
||
/** | ||
* Returns the ID of the parent role | ||
* @author KevinSwiggum | ||
*/ | ||
public String getParent() { | ||
return role.parentRoleId; | ||
} | ||
|
||
/** | ||
* returns the name of the role | ||
* @author KevinSwiggum | ||
*/ | ||
public String getTitle() { | ||
return role.name; | ||
} | ||
|
||
|
||
/** | ||
* Returns an HTML-formated string representing users within this role. Done here instead of VF because of the requirements of Google Visualization. Components didn't work well | ||
* @author KevinSwiggum | ||
*/ | ||
public String getRoleBody() { | ||
if (role != null) { | ||
//String roleBody = ''; | ||
String roleBody = '<div class="chartCell"> <div class="cellTitle">' + | ||
'<a href="javascript://nop/" onclick="loadMore(\''+role.id+'\');">'; | ||
|
||
if (!isExpanded) | ||
roleBody += '<img class="expandIcon" src="/s.gif" style="float:left;"/>'; | ||
|
||
roleBody += role.name + '</a></div><div style="clear:both;"></div>'; | ||
|
||
if (role.users.size() > 0) { | ||
String template = '<a target="_blank" href="/{!id}" title="View Profile">'; | ||
if (chatterEnabled) { | ||
template += '<img class="chartCellIcon" src="{!SmallPhotoUrl}"/>'; | ||
} | ||
template += '<div class="cellTitle">{!name}</div>' + | ||
'<div class="chartCellBody" style="margin:0px;padding:1px;">{!title}</div>' + | ||
'<div class="chartCellBody" style="margin:0px;padding:1px;">{!email}</div>' + | ||
'<div class="chartCellBody" style="margin:0px;padding:1px;">{!phone}</div>' + | ||
'</a><div style="clear:both;height:10px;"></div>'; | ||
|
||
|
||
for (User u : role.users) { | ||
String uBody = template; | ||
uBody = replace(uBody, 'id', u); | ||
if (chatterEnabled) uBody = replace(uBody,'SmallPhotoUrl', u); | ||
uBody = replace(uBody,'name', u); | ||
uBody = replace(uBody,'title', u); | ||
uBody = replace(uBody,'email', u); | ||
uBody = replace(uBody,'phone', u); | ||
|
||
roleBody += uBody; | ||
|
||
} | ||
} else { | ||
roleBody += '<i>No Users Defined</i>'; | ||
} | ||
|
||
roleBody += '</div>'; | ||
return roleBody; | ||
} | ||
return ''; | ||
} | ||
|
||
} | ||
|
||
/** | ||
* replaces template string with an object's value | ||
* @author KevinSwiggum | ||
*/ | ||
static String replace(String inString, String key, sObject o) { | ||
|
||
String objectValue = ''; | ||
try { | ||
Object obj = o.get(key); | ||
objectValue = obj != null ? String.valueOf(obj) : ''; | ||
|
||
} catch (Exception e) {} | ||
|
||
|
||
return inString.replace('{!' + key + '}', objectValue); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<apiVersion>20.0</apiVersion> | ||
<status>Active</status> | ||
</ApexClass> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/** | ||
* @author KevinSwiggum | ||
* Copyright 2011 Radial Web Solutions LLC | ||
*/ | ||
public with sharing class OrgChartController { | ||
|
||
transient List<OrgChart.RoleWithUsers> rolesWithUsersList; | ||
public String roleId {get; set;} | ||
private Set<ID> selectedRoleIds = new Set<ID>(); | ||
|
||
/** | ||
* Constructor grabs the top level role(s) and their direct children | ||
* @author KevinSwiggum | ||
*/ | ||
public OrgChartController() { | ||
init(); | ||
} | ||
|
||
/** | ||
* sets the initial set of role ids to just the top role ids | ||
* @author KevinSwiggum | ||
*/ | ||
private void init() { | ||
selectedRoleIds = OrgChart.getTopUserRoleIds(); | ||
} | ||
|
||
/** | ||
* sets the role list back to null so that it will be re-pulled | ||
* @author KevinSwiggum | ||
*/ | ||
private void clearRoleList() { | ||
rolesWithUsersList = null; | ||
} | ||
|
||
/** | ||
* populates a list of RoleWithUsers object for the given selectedRoleIds | ||
* @author KevinSwiggum | ||
*/ | ||
public List<OrgChart.RoleWithUsers> getRolesWithUsersList() { | ||
if (rolesWithUsersList == null) { | ||
rolesWithUsersList = OrgChart.getRolesWithUsers(selectedRoleIds); | ||
} | ||
return rolesWithUsersList; | ||
} | ||
|
||
/** | ||
* user clicked on a role to load children for that role | ||
* @author KevinSwiggum | ||
*/ | ||
public PageReference loadMore() { | ||
if (roleId != null) { | ||
selectedRoleIds.add(roleId); | ||
clearRoleList(); | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Pull all roles in the organization | ||
* @author KevinSwiggum | ||
*/ | ||
public PageReference expandAll() { | ||
selectedRoleIds = OrgChart.getAllRoleIds(); | ||
clearRoleList(); | ||
|
||
return Page.OrgChart; | ||
} | ||
|
||
/** | ||
* Collapse back down to the default view (parent and direct children) | ||
* @author KevinSwiggum | ||
*/ | ||
public PageReference collapseAll() { | ||
clearRoleList(); | ||
init(); | ||
return Page.OrgChart; | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<apiVersion>20.0</apiVersion> | ||
<status>Active</status> | ||
</ApexClass> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** | ||
* @author KevinSwiggum | ||
* Copyright 2011 Radial Web Solutions LLC | ||
*/ | ||
@isTest | ||
private class OrgChartTests { | ||
|
||
|
||
static testMethod void testOrgChart() { | ||
Set<ID> roleIds = OrgChart.getTopUserRoleIds(); | ||
List<OrgChart.RoleWithUsers> roleList = OrgChart.getRolesWithUsers(roleIds); | ||
for (OrgChart.RoleWithUsers rwu : roleList) { | ||
rwu.getParent(); | ||
rwu.getId(); | ||
rwu.getTitle(); | ||
rwu.getRoleBody(); | ||
} | ||
|
||
roleIds = OrgChart.getAllRoleIds(); | ||
System.assert(roleIds.size() > 0); | ||
} | ||
|
||
public static testMethod void testOrgChartController() { | ||
OrgChartController ctl = new OrgChartController(); | ||
List<OrgChart.RoleWithUsers> roleList = ctl.getRolesWithUsersList(); | ||
OrgChart.RoleWithUsers lastVal = roleList[roleList.size()-1]; | ||
ctl.roleId = lastVal.getId(); | ||
ctl.loadMore(); | ||
roleList = ctl.getRolesWithUsersList(); | ||
|
||
System.assert(roleList.size() > 0); | ||
ctl.expandAll(); | ||
ctl.collapseAll(); | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<apiVersion>20.0</apiVersion> | ||
<status>Active</status> | ||
</ApexClass> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Package xmlns="http://soap.sforce.com/2006/04/metadata"> | ||
<types> | ||
<members>*</members> | ||
<name>ApexClass</name> | ||
</types> | ||
<types> | ||
<members>*</members> | ||
<name>ApexComponent</name> | ||
</types> | ||
<types> | ||
<members>*</members> | ||
<name>ApexPage</name> | ||
</types> | ||
<types> | ||
<members>*</members> | ||
<name>ApexTrigger</name> | ||
</types> | ||
<types> | ||
<members>*</members> | ||
<name>CustomApplication</name> | ||
</types> | ||
<types> | ||
<members>*</members> | ||
<name>CustomTab</name> | ||
</types> | ||
<types> | ||
<members>*</members> | ||
<name>StaticResource</name> | ||
</types> | ||
<version>20.0</version> | ||
</Package> |
Oops, something went wrong.