Allow user to create a filter rule for Out of office emails in Salesforce.com
There are many occurrence specially where we are enabling user to add dynamic rules , this requires us to replicate the product search screen where user can select an object where we can fetch the related field using dynamic apex and then add a pick-list where user can select the condition like EQUAL , INCLUDES. Which can be used to create rules which can be picked in Apex.
Use case : Allow user to create a filter rule for Out of office email filter
Here is the sample code to create this screen.
Page :-
<apex:page sidebar="false" controller="RuleManagerController">
<apex:sectionHeader subtitle="Rule Manager"/>
<style>
.slds-button--brand.slds-button { margin-bottom:0.5rem; color: #fff; border: 1px solid #0070d2; background: #0070d2; font-size: 1em; padding: 2px 3px;}
</style>
<script type="text/javascript">
function newPopup(url) {
popupWindow = window.open(url,'popUpWindow','height=500,width=900,left=10,top=10,resizable=yes,scrollbars=yes,toolbar=no,menubar=no,location=no,directories=no,status=yes')
}
function clearAll(){
var inputElems = document.getElementsByTagName("input");
for(var i=0; i< inputElems.length; i++){
if (inputElems[i].type === "text"){
inputElems.value = "";
}
}
}
</script>
<apex:outputPanel id="dummy"/>
<apex:form id="theForm">
<div class="bOverviewSearch" width="50%">
<div class="view">
<b style="color:blue">Choose the Object and respective field, then click "Create Rule" to create rule.</b>
</div>
</div>
<apex:pageBlock title="Select rule Criteria">
<apex:outputpanel style="float:left;width:100%">
<div class="searchFilterFieldsHolder searchFilterFieldsHolderFirst" id="searchArea">
<table class="searchFilterFields" width="100%">
<tbody id="theTBody1">
<tr>
<td style="width:5%">
<span class="inputTitle" style="font-weight:bold">Select Object</span>
<br/>
<apex:SelectList value="{!strObjectName}" size="1" style="font-family: Arial;font-size: 11px;" >
<apex:actionSupport event="onchange" status="status2" reRender="fieldlist"/>
<apex:selectOptions value="{!Objects}"></apex:selectOptions>
</apex:SelectList>
</td>
<td style="width:5%">
<span class="inputTitle" style="font-weight:bold">Select Field</span>
<br/>
<apex:selectList value="{!selectedFilter}" size="1" style="font-family: Arial;font-size: 11px;" id="fieldlist">
<apex:selectOptions value="{!Fields}"/>
<apex:actionSupport event="onchange" action="{!populateOperatorOptions}" reRender="{!$Component.OperatorsMenu},{!$Component.filterStringText}" status="status2"/>
</apex:selectList>
</td>
<td style="width:5%">
<span class="inputTitle" style="font-weight:bold">Condition</span>
<br/>
<apex:selectList value="{!selectedOperator}" size="1" style="font-family: Arial;font-size: 11px;" id="OperatorsMenu">
<apex:selectOptions value="{!operatorOptions}"/>
</apex:selectList>
</td>
<td style="width:5%">
<span class="inputTitle" style="font-weight:bold">Value</span>
<br/>
<apex:outputPanel id="filterStringText">
<apex:inputText value="{!filterString}" style="font-family: Arial;font-size: 11px;" size="20" rendered="{!if(fieldPicklistvalues.size == 0,true,false)}"/>
<apex:selectList value="{!filterString}" size="1" style="font-family: Arial;font-size: 11px;" rendered="{!if(fieldPicklistvalues.size > 0,true,false)}">
<apex:selectOptions value="{!fieldPicklistvalues}"/>
</apex:selectList>
</apex:outputPanel>
</td>
<td>
<span/>
<br/>
<apex:actionStatus id="status2">
<apex:facet name="start">
<div style="width: 1300px;">
<img src="/img/loading24.gif" style="vertical-align:middle;"/>
<span style="margin-left: 10px; font-size: 12px; font-weight: bold; color: #000000;">Please wait...</span>
</div>
</apex:facet>
</apex:actionStatus>
</td>
</tr>
<tr id="ruleInfo">
<td colspan="4" style="width:100%">
<span class="inputTitle" style="font-weight:bold">Enter rule Body</span>
<br/>
<apex:inputTextarea cols="100" value="{!ruleCommnet}" style="font-family: Arial;font-size: 13px;" rows="5"/>
</td>
</tr>
<tr id="filterInfo">
<td colspan="4" >
<apex:outputPanel id="errorpanel" >
<br/>
<apex:pageMessages />
</apex:outputPanel>
</td>
</tr>
</tbody>
</table>
</div>
</apex:outputpanel>
</apex:pageBlock>
<apex:outputPanel id="outputpanelId">
<apex:pageBlock title="All rule Rules" id="results" rendered="{!results.size > 0}">
<apex:pageBlockTable value="{!results}" var="res">
<apex:column headerValue="isActive">
<apex:outputField value="{!res.isActive__c}"/>
</apex:column>
<apex:column headerValue="Object">
<apex:outputField value="{!res.Object__c}"/>
</apex:column>
<apex:column headerValue="Field">
<apex:outputField value="{!res.Field_Name__c}"/>
</apex:column>
<apex:column headerValue="Operator">
<apex:outputField value="{!res.Operator__c}"/>
</apex:column>
<apex:column headerValue="Value">
<apex:outputField value="{!res.Value__c}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
<apex:pageBlock id="noResultsBlock" rendered="{!results.size == 0}">
<apex:outputPanel >No records to display.</apex:outputPanel>
</apex:pageBlock>
</apex:outputPanel>
</apex:form>
</apex:page>
Controller Class :-
public with sharing class RuleManagerController {
public Map<String, Schema.SoapType> additionalFiltersTypeMap;
public Map<String, Schema.SOAPType> fieldTypeMap;
public Map<Integer, FilterWrapper> extraFiltersMap {get;set;}
public String selectedFilter {get;set;}
public String selectedOperator {get;set;}
public String notificationCommnet {get;set;}
public String filterString {get;set;}
public List<String> operatorsList {get;set;}
public List<SelectOption> filterOptions {get;set;}
public Boolean invalidFormat {get;set;}
public String filterErrorMessage{get;set;}
public List<SelectOption> operatorOptions {get;set;}
public Set<String> multiSelectMenuSet;
public list<SelectOption> fieldPicklistvalues{get;set;}
public String strFieldName { get; set;}
public String strObjectName{get; set;}
private Set<String> ignoreSet;
public List<Rule__c> results {get;set;}
public Map<String,List<String>> mapPickListValues;
public Map<String,String> fieldnameAPIMap = new Map<String,String>();
public integer m_pageNumber = 0;
public integer m_totalRecords = 0;
private Integer CURRENT_PAGE_SIZE = 10;
public List<Rule__c> paginatedResults {get;set;}
public List<Rule__c> displayRecord {get;set;}
public Integer recordNumberDisplayed {get;set;}
public String selectedID {get;set;}
// Constructor
public NotificationManagerController(){
results = new List<Rule__c>();
String productObjName = 'Account';
extraFiltersMap = new Map<Integer, filterWrapper>();
fieldTypeMap = new Map<String, Schema.SOAPType>();
operatorsList = new List<String>{'equals', 'not equal to', 'starts with', 'contains', 'does not contain', 'less than', 'greater than', 'less or equal', 'greater or equal', 'includes', 'excludes'};
filterOptions = new List<SelectOption>();
invalidFormat = false;
multiSelectMenuSet = new Set<String>();
filterOptions.add(new SelectOption('','--None--'));
additionalFiltersTypeMap = new Map<String,Schema.SoapType>{'Owner.Name' => SoapType.ID};
ignoreSet = new Set<String>{'CreatedByIdId','LastViewedDate','LastReferencedDate','CurrencyIsoCode','RecordId','IsDeleted','LastModifiedById','Id','SystemModstamp','RecordTypeId'};
fieldPicklistvalues = new List<SelectOption>();
paginatedResults = new List<Rule__c>();
String queryString='';
// Fetch the fields from rule table
queryString = 'Select id , Body__c , Field_Name__c , Object__c , Operator__c , Value__c , isActive__c from Rule__c';
try{
List<Rule__c> queryResult = (List<Rule__c>)Database.Query(queryString);
results = new List<Rule__c>();
for(Rule__c nrule : queryResult){
results.add(nrule);
}
system.debug('results ::' + results);
} catch(Exception ex){
Apexpages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'An unexpected exception occured. Please contact your System Admin'));
System.debug('###Exception : '+ex.getMessage());
}
}
public List<SelectOption> getObjects(){
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('','--SELECT--'));
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
Set<String> standardObjects = new Set<String>();
for(Schema.SObjectType d : gd.values()){
Schema.DescribeSObjectResult ds = d.getDescribe();
if(!ds.isCreateable())
continue;
standardObjects.add(ds.getName());
}
options.add(new SelectOption('Account','Account'));
options.add(new SelectOption('Case','Case'));
options.add(new SelectOption('Contact','Contact'));
options.add(new SelectOption('Lead','Lead'));
options.add(new SelectOption('Opportunity','Opportunity'));
options.sort();
return options;
}
public List<selectOption> getFields(){
List<SelectOption> options = new List<SelectOption>();
List<SelectOption> filterOptions = new List<SelectOption>();
filterOptions.add(new SelectOption('','--None--'));
system.debug('****strObjectName****' + strObjectName);
// Get picklist Map
mapPickListValues = new Map<String,List<String>>();
if(strObjectName!=null && !''.equals(strObjectName)){
Map<String, Schema.SObjectField> objectFields = Schema.getGlobalDescribe().get(strObjectName).getDescribe().fields.getMap();
for(Schema.SObjectField s : objectFields.values())
{
// Remove unwanted fields.
if(!ignoreSet.contains(s.getDescribe().getName())){
filterOptions.add(new SelectOption(s.getDescribe().getName(),s.getDescribe().getLabel()));
fieldTypeMap.put(s.getDescribe().getName(), s.getDescribe().getSoapType());
//Populate field API
fieldnameAPIMap.put(s.getDescribe().getLabel(),s.getDescribe().getName());
// Get picklist
Schema.DescribeFieldResult fieldResult = s.getDescribe();
if(fieldResult.getPicklistValues()!=null){
List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
List<String> lstPickvals = new List<String>();
for( Schema.PicklistEntry f : ple){
lstPickvals.add(f.getValue());
}
mapPickListValues.put(s.getDescribe().getName(),lstPickvals);
}
}
}
}
populateOperatorOptions();
filterOptions.sort();
system.debug('****fieldnameAPIMap****' + fieldnameAPIMap);
return filterOptions;
}
public void getCondition(String field, String operator, String value){
try{
System.debug('@@@@@@'+fieldTypeMap);
String returnString = '';
Schema.SoapType fieldType;
if(field == '' || field == NULL || operator == '' || operator == NULL || value == '' || value == NULL){
return ;
}
Boolean isValid = validateCondition(field, value);
System.debug('isValid::'+isValid);
if(!isValid){
invalidFormat = true;
Schema.SoapType fType;
if(fieldTypeMap.containsKey(field)){
fType = fieldTypeMap.get(field);
}
if(fType == SoapType.Boolean){
filterErrorMessage = field +' has to be either True or False.';
Apexpages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,filterErrorMessage));
}else if(fType == SoapType.Integer || fType == SoapType.Double){
filterErrorMessage = field +' has to be in the range 0-9.';
Apexpages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,filterErrorMessage));
}else if(fType == SoapType.DateTime){
filterErrorMessage = field +' has to be in the format yyyy-mm-dd hh:mm:ss.';
Apexpages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,filterErrorMessage));
}else if(fType == SoapType.Date){
filterErrorMessage = field +' has to be in the format yyyy-mm-dd.';
Apexpages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,filterErrorMessage));
}
return ;
} else{
invalidFormat = false;
}
}
catch(Exception e){
system.debug('...........'+e);
return ;
}
}
public Boolean validateCondition(String field, String value){
Boolean returnBoolean = false;
Schema.SoapType fieldType;
if(fieldTypeMap.containsKey(field)){
fieldType = fieldTypeMap.get(field);
}else if(additionalFiltersTypeMap.containsKey(field)){
fieldType = additionalFiltersTypeMap.get(field);
}
system.debug('****' + fieldType);
if(fieldType == SoapType.Integer || fieldType == SoapType.Double){
Pattern numberFormat = Pattern.Compile('^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$');
Matcher numberMatch = numberFormat.matcher(value);
if(numberMatch.Matches()){
returnBoolean = true;
}
} else if(fieldType == SoapType.Boolean){
if(value.equalsIgnoreCase('TRUE') || value.equalsIgnoreCase('FALSE') || value == '0' || value == '1'){
returnBoolean = true;
}
} else if(fieldType == SoapType.Date){
if(value.equalsIgnoreCase('TODAY')){
returnBoolean = true;
} else{
Pattern dateFormat = Pattern.Compile('(^\\(?(\\d{4})\\)?[- ]?(\\d{2})[- ]?(\\d{2})$)');
Matcher dateMatch = dateFormat.Matcher(value);
if(dateMatch.Matches()){
returnBoolean = true;
}
}
} else if(fieldType == SoapType.DateTime){
if(value.equalsIgnoreCase('NOW')){
returnBoolean = true;
} else{
Pattern dateTimeFormat = Pattern.Compile('(^\\(?(\\d{4})\\)?[- ]?(\\d{2})[- ]?(\\d{2})[ ]?(\\d{2})[: ]?(\\d{2})[: ]?(\\d{2})$)');
Matcher dateTimeMatch = dateTimeFormat.Matcher(value);
if(dateTimeMatch.Matches()){
returnBoolean = true;
}
}
} else if(fieldType == SoapType.String){
returnBoolean = true;
}
else if(fieldType == SoapType.Id){
returnBoolean = true;
}
System.debug('returnBoolean ::'+returnBoolean );
return returnBoolean;
}
public Class FilterWrapper{
public List<SelectOption> fOptions {get; set;}
public List<SelectOption> oOptions {get; set;}
public List<SelectOption> pOptions {get; set;}
public String fSelected {get; set;}
public String oSelected {get; set;}
public String value {get; set;}
public List<String> allOperators;
public Map<String, Schema.SoapType> fieldTypeMap;
public Set<String> multiSelectMenuSet;
public Map<String, Schema.SoapType> additionalFiltersTypeMap;
public boolean isPickList{get; set;}
public FilterWrapper(List<SelectOption> fOptions, List<String> operators, Map<String, Schema.SoapType> ftMap, Set<String> mmSet, Map<String, Schema.SoapType> afMap){
this.fOptions = new List<SelectOption>();
this.fOptions = fOptions;
this.allOperators = new List<String>();
this.allOperators = operators;
fieldTypeMap = new Map<String, Schema.SoapType>();
fieldTypeMap = ftMap;
additionalFiltersTypeMap = new Map<String, Schema.SoapType>();
additionalFiltersTypeMap = afMap;
multiSelectMenuSet = new Set<String>();
multiSelectMenuSet = mmSet;
oOptions = new List<SelectOption>();
oOptions.add(new SelectOption('', '--None--'));
for(String str : allOperators){
oOptions.add(new SelectOption(str, str));
}
isPickList = false;
}
public void populateOperatorOptions(){
oOptions = new List<SelectOption>();
oOptions.add(new SelectOption('','--None--'));
List<String> filteredOperators = new List<String>();
if(fSelected == '' || fSelected == NULL){
filteredOperators = allOperators;
} else{
Schema.SoapType fieldType;
if(fieldTypeMap.containsKey(fSelected)){
fieldType = fieldTypeMap.get(fSelected);
} else if(additionalFiltersTypeMap.containsKey(fSelected)){
fieldType = additionalFiltersTypeMap.get(fSelected);
}
if(fieldType == SoapType.Boolean){
filteredOperators = new List<String>{'equals', 'not equal to'};
} else if(fieldType == SoapType.Integer || fieldType == SoapType.Double || fieldType == SoapType.Date || fieldType == SoapType.DateTime || fieldType == SoapType.Time){
filteredOperators = new List<String>{'equals', 'not equal to', 'less than', 'greater than', 'less or equal', 'greater or equal'};
} else if(fieldType == SoapType.String || fieldType == SoapType.ID){
filteredOperators = new List<String>{'equals', 'not equal to', 'starts with', 'contains', 'does not contain', 'less than', 'greater than', 'less or equal', 'greater or equal'};
if(multiSelectMenuSet.contains(fSelected)){
filteredOperators.add('includes');
filteredOperators.add('excludes');
}
}
}
for(String str : filteredOperators){
oOptions.add(new SelectOption(str, str));
}
isPickList = false;
pOptions = new List<SelectOption>();
pOptions.add(new SelectOption('', '--None--'));
}
}
public PageReference populateOperatorOptions(){
operatorOptions = new List<SelectOption>();
//filterString = '';
operatorOptions.add(new SelectOption('','--None--'));
List<String> filteredOperators = new List<String>();
if(selectedFilter == '' || selectedFilter == NULL){
filteredOperators = operatorsList;
} else{
Schema.SoapType fieldType;
if(fieldTypeMap.containsKey(selectedFilter)){
fieldType = fieldTypeMap.get(selectedFilter);
}else if(additionalFiltersTypeMap.containsKey(selectedFilter)){
fieldType = additionalFiltersTypeMap.get(selectedFilter);
}
if(fieldType == SoapType.Boolean){
filteredOperators = new List<String>{'equals', 'not equal to'};
} else if(fieldType == SoapType.Integer || fieldType == SoapType.Double || fieldType == SoapType.Date || fieldType == SoapType.DateTime || fieldType == SoapType.Time){
filteredOperators = new List<String>{'equals', 'not equal to', 'less than', 'greater than', 'less or equal', 'greater or equal'};
} else if(fieldType == SoapType.String || fieldType == SoapType.ID){
filteredOperators = new List<String>{'equals', 'not equal to', 'starts with', 'contains', 'does not contain', 'less than', 'greater than', 'less or equal', 'greater or equal'};
if(multiSelectMenuSet.contains(selectedFilter)){
filteredOperators.add('includes');
filteredOperators.add('excludes');
}
}
}
for(String str : filteredOperators){
operatorOptions.add(new SelectOption(str, str));
}
System.debug('SelectedFilter******'+selectedFilter);
if(mapPickListValues!=null && !mapPickListValues.isEmpty()){
System.debug('MapValues&&&&'+mapPickListValues);
fieldPicklistvalues = new List<SelectOption>();
if(mapPickListValues.containsKey(selectedFilter)){
for(String s : mapPickListValues.get(selectedFilter)){
fieldPicklistvalues.add(new SelectOption (s,s));
}
System.debug('MapValues&&&&'+mapPickListValues+'&&&&&'+fieldPicklistvalues);
}
}
return NULL;
}
}
Comments
Post a Comment