SessionIdPage:
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
<apex:page > | |
Start_Of_Session_Id{!$Api.Session_ID}End_Of_Session_Id | |
</apex:page> |
UtilsClass:
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
global class UtilsClass { | |
global static String getSessionIdFromVFPage(PageReference visualforcePage){ | |
String content = visualforcePage.getContent().toString(); | |
Integer s = content.indexOf('Start_Of_Session_Id') + 'Start_Of_Session_Id'.length(), | |
e = content.indexOf('End_Of_Session_Id'); | |
system.debug('Session ID: ' + content.substring(s, e)); | |
return content.substring(s, e); | |
} | |
} |
searchMetadataCntrl:
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
/* Name: searchMetadataCntrl | |
* Description: This Apex class makes callout to Salesforce Tooling Api and get the metadata information about the objects. | |
* Created Date: 15/06/2018 | |
* LastModifiedDate: 15/06/2018 | |
* Created By: Arun Kumar | |
*/ | |
public class searchMetadataCntrl { | |
@AuraEnabled | |
public static string GetMetaData(string type){ | |
HttpRequest req = new HttpRequest(); | |
String session_id; | |
if(!test.isRunningTest()){ | |
session_id = UtilsClass.getSessionIdFromVFPage(Page.SessionIdPage); | |
} | |
system.debug('Session ID: ' +session_id); | |
req.setHeader('Authorization', 'Bearer ' + session_id); | |
string domainUrl=URL.getSalesforceBaseUrl().toExternalForm(); | |
string endpoint=''; | |
if(type=='ApexClass & ApexTrigger'){ | |
endpoint='select+id,ApexClassOrTrigger.Name,NumLinesCovered,NumLinesUncovered+from+ApexCodeCoverageAggregate'; | |
} | |
else if(type=='ValidationRule'){ | |
endpoint='Select+id,ErrorDisplayField,createdDate,ValidationName+from+ValidationRule'; | |
} | |
else if(type=='WorkflowRule'){ | |
endpoint='Select+id,Name+from+WorkflowRule'; | |
} | |
else if(type=='VisualforcePages'){ | |
endpoint='Select+id,Name,Description,ControllerType,ApiVersion+from+ApexPage'; | |
}else if(type=='Static Resource'){ | |
endpoint='select+id,Name,ContentType+from+StaticResource'; | |
}else if(type=='Email Template'){ | |
endpoint='select+id,Name,UIType+from+EmailTemplate'; | |
}else if(type=='Documents'){ | |
endpoint='select+id,Name,Type,Url+from+Document'; | |
}else if(type=='Visualforce Component'){ | |
endpoint='select+id,name+from+ApexComponent'; | |
} | |
req.setEndpoint(domainUrl+'/services/data/v42.0/tooling/query/?q='+endpoint); | |
req.setMethod('GET'); | |
Http h = new Http(); | |
try{ | |
HttpResponse response = h.send(req); | |
system.debug(response.getBody()); | |
return response.getBody(); | |
} | |
catch(Exception e){ | |
string exceptionString=e.getMessage(); | |
system.debug('Exception: '+exceptionString); | |
return exceptionString; | |
} | |
} | |
} |
SearchMetadataCmp:
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
<aura:component controller="searchMetadataCntrl" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" > | |
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/> | |
<aura:attribute name="Result" type="Object"/> | |
<aura:attribute name="metadataType" type="string[]"/> | |
<aura:attribute name="selectedMetadata" type="string"/> | |
<aura:attribute name="searchKeyword" type="string"/> | |
<aura:attribute name="unFilteredResult" type="object"/> | |
<aura:handler event="aura:waiting" action="{!c.showSpinner}"/> | |
<aura:handler event="aura:doneWaiting" action="{!c.hideSpinner}"/> | |
<aura:attribute name="Spinner" type="boolean" default="false"/> | |
<aura:attribute name="isApexType" type="boolean" default="false"/> | |
<aura:attribute name="searchPlaceHolder" type="string"/> | |
<aura:attribute name="TotalRecReturned" type="Integer"/> | |
<aura:attribute type="String" name="headerBgColor" /> | |
<aura:attribute type="String" name="bodyBgColor" /> | |
<aura:attribute name="headerTextColor" type="string"/> | |
<aura:attribute name="bodyTextColor" type="string"/> | |
<aura:attribute name="showSettings" type="boolean" default="false"/> | |
<div class="slds"> | |
<div class="slds-page-header slds-theme_shade slds-theme_alert-texture " style="{! 'background-color:' + v.headerBgColor }"> | |
<span style="{! 'color:' + v.headerTextColor }">Metadata Search</span> | |
<!--<a href="" onclick="{!c.toggleSettings}" id="settingIcon"> | |
<lightning:icon iconName="utility:settings" alternativeText="setting" size="xx-small"/> | |
</a>--> | |
</div> | |
<!-- Starting Page--> | |
<div> | |
</div> | |
<!--End--> | |
<div class="bodyPart" style="{! 'background-color:' + v.bodyBgColor }"> | |
<div style="{! 'color:' + v.bodyTextColor }"> | |
<lightning:select name="selectItem" label="Select an item" onchange="{!c.OnSelectChange}"> | |
<aura:iteration items="{!v.metadataType}" var="m"> | |
<option value="{!m}" label="{!m}" /> | |
</aura:iteration> | |
</lightning:select> | |
<lightning:input label="Search" placeholder="{!v.searchPlaceHolder}" value="{!v.searchKeyword}" onkeyup="{!c.SearchMethod}"></lightning:input> | |
<br/> | |
<aura:if isTrue="{!v.Spinner}"> | |
<div aura:id="spinnerId" class="slds-spinner_container"> | |
<div class="slds-spinner--brand slds-spinner slds-spinner--large slds-is-relative" role="alert"> | |
<span class="slds-assistive-text">Loading</span> | |
<div class="slds-spinner__dot-a"></div> | |
<div class="slds-spinner__dot-b"></div> | |
</div> | |
</div> | |
</aura:if> | |
<aura:if isTrue="{!v.Result !=null}"> | |
<div class="slds-table--header-fixed_container hdr_container" style=" "> | |
<div class="searchResult"> | |
<table class="slds-table slds-table--bordered slds-max-medium-table_stacked-horizontal slds-table--header-fixed" aura:id="myTable"> | |
<thead> | |
<tr class="slds-text-title_caps"> | |
<th class="" scope="col"> | |
<div class="slds-truncate slds-cell-fixed thdr" title="Name">Name</div> | |
</th> | |
<th class=""> | |
<div class="slds-truncate slds-cell-fixed thdr" title="ID">ID</div> | |
</th> | |
<aura:if isTrue="{!v.isApexType}"> | |
<th class="slds-cell-shrink" scope="col"> | |
<div class="slds-truncate slds-cell-fixed thdr" title="Type">Type</div> | |
</th> | |
<th class="" scope="col"> | |
<div class="slds-truncate slds-cell-fixed thdr" title="NumLines Covered">Lines Cov.</div> | |
</th> | |
<th class="" scope="col"> | |
<div class="slds-truncate slds-cell-fixed thdr" title="NumLines Uncovered">Lines Uncov.</div> | |
</th> | |
</aura:if> | |
</tr> | |
</thead> | |
<tbody> | |
<aura:iteration items="{!v.Result}" var="r"> | |
<tr class="slds-hint-parent trow" > | |
<td class="slds-cell-shrink" data-label="Select Row"><a aura:id="trow" href="" id="{!r.Id}" onclick="{!c.navigate}">{!r.Name}</a></td> | |
<td class="slds-cell-shrink" data-label="Select Row">{!r.Id}</td> | |
<td class="slds-cell-shrink" data-label="Select Row">{!r.Type}</td> | |
<td class="slds-cell-shrink" data-label="Select Row">{!r.NumLinesCovered}</td> | |
<td class="slds-cell-shrink" data-label="Select Row">{!r.NumLinesUncovered}</td> | |
</tr> | |
</aura:iteration> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
<br/> | |
<p> Total {!v.TotalRecReturned} Records Returned.</p> | |
</aura:if> | |
</div> | |
</div> | |
</div> | |
</aura:component> |
SearchMetadataCmpController:
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
({ | |
doInit : function(component, event, helper) { | |
var type=['ApexClass & ApexTrigger','ValidationRule','WorkflowRule','VisualforcePages','Static Resource','Email Template','Documents','Visualforce Component']; | |
component.set("v.metadataType",type); | |
component.set("v.selectedMetadata",'ApexClass & ApexTrigger'); | |
helper.GetSearchedData(component,event,helper); | |
}, | |
OnSelectChange:function(component,event,helper){ | |
var selected=event.getSource().get("v.value"); | |
console.log('selectted: ' +selected); | |
component.set("v.searchPlaceHolder",'Search '+selected); | |
component.set("v.selectedMetadata",selected); | |
if(selected=='--None--'){ | |
component.set("v.Result",null); | |
}else{ | |
helper.GetSearchedData(component,event,helper); | |
} | |
}, | |
showSpinner: function(component, event, helper) { | |
component.set("v.Spinner", true); | |
}, | |
hideSpinner : function(component,event,helper){ | |
component.set("v.Spinner", false); | |
}, | |
navigate:function(component,event,helper){ | |
var idx = event.target.id; | |
var urlEvent = $A.get("e.force:navigateToURL"); | |
urlEvent.setParams({ | |
"url": "/"+idx, | |
"target": "_blank" | |
}); | |
urlEvent.fire(); | |
}, | |
SearchMethod:function(component,event,helper){ | |
var searchKeyWord=event.getSource().get("v.value"); | |
if(searchKeyWord!=''){ | |
helper.SearchItems(component,event,searchKeyWord); | |
}else{ | |
component.set("v.Result",component.get("v.unFilteredResult")); | |
} | |
} | |
}) |
SearchMetadataCmpHelper:
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
({ | |
GetSearchedData : function(component,event,helper) { | |
var action=component.get("c.GetMetaData"); | |
var selectedType=component.get("v.selectedMetadata"); | |
action.setParams({ | |
"type": component.get("v.selectedMetadata") | |
}); | |
action.setCallback(this,function(response){ | |
var state=response.getState(); | |
if(state=='SUCCESS'){ | |
var result=JSON.parse(response.getReturnValue()); | |
var returnedString = JSON.stringify(response.getReturnValue()); | |
if(returnedString.includes("Unauthorized endpoint, please check Setup")){ | |
//alert('Unauthorized end point'); | |
var sMsg ='Unauthorized endpoint, please goto Setup->Security->Remote site settings '; | |
sMsg+='and add a remote site setting (endpoint = https://your_domain-dev-ed.my.salesforce.com/)'; | |
var toastEvent = $A.get("e.force:showToast"); | |
toastEvent.setParams({ | |
mode: 'sticky', | |
message: sMsg, | |
type : 'warning' | |
}); | |
toastEvent.fire(); | |
} | |
else{ | |
console.log('result size: ' +result.size); | |
console.log('result: '+ JSON.stringify(result)); | |
component.set("v.TotalRecReturned",result.size); | |
var arrayData=new Array(); | |
if(selectedType=='ApexClass & ApexTrigger'){ | |
component.set("v.isApexType",true); | |
for(var i=0; i<result.records.length;i++){ | |
if(result.records[i].ApexClassOrTrigger !=null){ | |
var str=result.records[i].ApexClassOrTrigger.attributes.url; | |
var rest = str.substring(0, str.lastIndexOf("/") ); | |
var Ids = str.substring(str.lastIndexOf("/") + 1, str.length); | |
var mType = rest.substring(rest.lastIndexOf("/") + 1, rest.length); | |
var obj={"Id":Ids, | |
"Name":result.records[i].ApexClassOrTrigger.Name.toUpperCase(), | |
"Type":mType, | |
"NumLinesCovered":result.records[i].NumLinesCovered, | |
"NumLinesUncovered":result.records[i].NumLinesUncovered}; | |
arrayData.push(obj); | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
} | |
} | |
if(selectedType=='ValidationRule'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].ValidationName, | |
"TableEnumOrId":result.records[i].ValidationName} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
if(selectedType=='WorkflowRule'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].Name, | |
"TableEnumOrId":result.records[i].TableEnumOrId} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
if(selectedType=='VisualforcePages'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].Name, | |
} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
if(selectedType=='Static Resource'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].Name.toUpperCase(), | |
} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
if(selectedType=='Email Template'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].Name.toUpperCase(), | |
} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
if(selectedType=='Documents'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].Name.toUpperCase(), | |
} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
if(selectedType=='Visualforce Component'){ | |
component.set("v.isApexType",false); | |
for(var i=0; i<result.records.length;i++){ | |
var obj={"Id":result.records[i].Id, | |
"Name":result.records[i].Name.toUpperCase(), | |
} | |
arrayData.push(obj); | |
} | |
component.set("v.Result",arrayData); | |
component.set("v.unFilteredResult",arrayData); | |
} | |
} | |
} | |
}); | |
$A.enqueueAction(action); | |
}, | |
SearchItems:function(component,event,searchKey){ | |
console.log('Search Key: ' +searchKey); | |
var arrayForSearch=component.get("v.Result"); | |
var NameArray=new Array(); | |
for(var i=0; i<arrayForSearch.length; i++){ | |
var obj={"Id":arrayForSearch[i].Id, | |
"Name":arrayForSearch[i].Name.toUpperCase(), | |
"Type":arrayForSearch[i].Type, | |
"NumLinesCovered":arrayForSearch[i].NumLinesCovered, | |
"NumLinesUncovered":arrayForSearch[i].NumLinesUncovered}; | |
NameArray.push(obj); | |
} | |
var resultArray=new Array(); | |
for (var j=0; j<NameArray.length; j++) { | |
if(searchKey!=''){ | |
if (NameArray[j].Name.toString().match (searchKey.toUpperCase())) | |
{ | |
console.log('Matching: '); | |
resultArray.push(NameArray[j]); | |
component.set("v.Result",resultArray); | |
} | |
} | |
else{ | |
} | |
} | |
} | |
}) |
SearchMetadataCmpCSS:
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
.THIS .changeMe{ | |
display: ""; | |
color:red; | |
background-color:yellow; | |
} | |
.THIS .ul_list{ | |
padding:10px; | |
} | |
.THIS .slds-page-header { | |
border-radius: 0px; | |
} | |
.THIS .RemoveMe{ | |
display: "none"; | |
} | |
.THIS .bodyPart{ | |
background-color:white; | |
padding:10px 10px 10px 10px; | |
} | |
.THIS .trow{ | |
height:35px; | |
} | |
.THIS .thdr{ | |
padding-top: 1.5%; | |
padding-left: 1%; | |
} | |
.THIS .searchResult{ | |
height:200px; | |
overflow-y: scroll; | |
border-radius:3px; | |
} | |
.THIS .hdr_container { | |
padding-top: 5%; | |
} | |
.THIS #settingIcon{ | |
float:right; | |
} | |
.THIS #settingDrpdwn{ | |
position: relative; | |
float: right; | |
right: 22%; | |
top: -2px; | |
} | |
.THIS .menu{ | |
width: 194px; | |
padding: 10px; | |
} | |
.THIS .slds-page-header{ | |
border-radius:none; | |
} |
Find the code on github here.
Happy Coding… 🙂
Thanks
Arun Kumar