Skip to content

Commit

Permalink
Initial commit for Optimizer component
Browse files Browse the repository at this point in the history
  • Loading branch information
afawcett committed Apr 23, 2018
1 parent cc22d58 commit 6571ab1
Show file tree
Hide file tree
Showing 25 changed files with 421 additions and 1 deletion.
4 changes: 3 additions & 1 deletion .forceignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
# More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm
#

package.xml
package.xml
**profiles
**settings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<label>Declarative Lookup Rollup Summaries</label>
<navType>Standard</navType>
<tabs>Welcome</tabs>
<tabs>LookupRollupSummariesHome</tabs>
<tabs>ManageLookupRollupSummaries</tabs>
<tabs>LookupRollupSummaryLog__c</tabs>
<uiType>Lightning</uiType>
Expand Down
12 changes: 12 additions & 0 deletions force-app/main/aura/optimizer/optimizer.cmp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<aura:component controller="OptimizerComponentController" implements="flexipage:availableForAllPageTypes" access="global">
<aura:attribute name="summary" type="object"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<lightning:card iconName="standard:account" title="Optimizer" footer="Declarative Lookup Rollup Summaries">
<p class="slds-p-horizontal_small">
<ui:message title="{!v.summary.title}" severity="{!v.summary.severity}" closable="false">{!v.summary.message}</ui:message>
<aura:iteration items="{!v.summary.notifications}" var="notification">
<c:optimizerNotification id="{!notification.id}" severity="{!notification.severity}" message="{!notification.message}"/>
</aura:iteration>
</p>
</lightning:card>
</aura:component>
5 changes: 5 additions & 0 deletions force-app/main/aura/optimizer/optimizer.cmp-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<AuraDefinitionBundle xmlns="urn:metadata.tooling.soap.sforce.com" fqn="optimizer">
<apiVersion>42.0</apiVersion>
<description>A Lightning Component Bundle</description>
</AuraDefinitionBundle>
2 changes: 2 additions & 0 deletions force-app/main/aura/optimizer/optimizer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.THIS {
}
3 changes: 3 additions & 0 deletions force-app/main/aura/optimizer/optimizer.design
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<design:component >

</design:component>
7 changes: 7 additions & 0 deletions force-app/main/aura/optimizer/optimizer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions force-app/main/aura/optimizer/optimizerController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
({
doInit : function(cmp) {
// Calls OptimizerService.analyze
var action = cmp.get("c.analyze");
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
cmp.set('v.summary', response.getReturnValue());
}
else if (state === "ERROR") {
var errors = response.getError();
if (errors) {
if (errors[0] && errors[0].message) {
console.log("Error message: " + errors[0].message);
}
} else {
console.log("Unknown error");
}
}
});
$A.enqueueAction(action);
}
})
5 changes: 5 additions & 0 deletions force-app/main/aura/optimizer/optimizerHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
({
helperMethod : function() {

}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<aura:component>
<aura:attribute name="id" type="string"/>
<aura:attribute name="message" type="string"/>
<aura:attribute name="severity" type="string"/>
<div class="slds-scoped-notification slds-media slds-media_center" role="status">
<lightning:icon iconName="{!'utility:'+v.severity}" variant="{!v.severity}" size="small" />
<div class="slds-media__body">
<p>&nbsp;{!v.message}&nbsp;<a href="{!v.id}">More Information</a></p>
</div>
</div>
</aura:component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<AuraDefinitionBundle xmlns="urn:metadata.tooling.soap.sforce.com" fqn="optimizerNotification">
<apiVersion>42.0</apiVersion>
<description>A Lightning Component Bundle</description>
</AuraDefinitionBundle>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.THIS {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<design:component >

</design:component>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
({
myAction : function(component, event, helper) {

}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
({
helperMethod : function() {

}
})
100 changes: 100 additions & 0 deletions force-app/main/classes/OptimizerComponentController.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* Copyright (c), Andrew Fawcett
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Andrew Fawcett, nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

public with sharing class OptimizerComponentController {

// Map notification status from the service to UI severity
private static Map<OptimizerService.NotificationStatus, String> mapNotificationStatusToUIServerity =
new Map<OptimizerService.NotificationStatus, String> {
OptimizerService.NotificationStatus.CheckFailed => 'error',
OptimizerService.NotificationStatus.Warning => 'info',
OptimizerService.NotificationStatus.Attention => 'warning'
};

// Map summary status from the service to UI severity
private static Map<OptimizerService.SummaryStatus, String> mapSummaryStatusToUIServerity =
new Map<OptimizerService.SummaryStatus, String> {
OptimizerService.SummaryStatus.Complete => 'info',
OptimizerService.SummaryStatus.CompleteWithWarnings => 'warning',
OptimizerService.SummaryStatus.CompleteNeedsAttention => 'error'
};
private static Map<OptimizerService.SummaryStatus, String> mapSummaryStatusToUITitle =
new Map<OptimizerService.SummaryStatus, String> {
OptimizerService.SummaryStatus.Complete => 'Status: Good',
OptimizerService.SummaryStatus.CompleteWithWarnings => 'Status: Warnings',
OptimizerService.SummaryStatus.CompleteNeedsAttention => 'Status: Errors'
};
private static Map<OptimizerService.SummaryStatus, String> mapSummaryStatusToUIMessage =
new Map<OptimizerService.SummaryStatus, String> {
OptimizerService.SummaryStatus.Complete => 'It looks like you are all good for the moment, check back again regularly!',
OptimizerService.SummaryStatus.CompleteWithWarnings => 'It looks like you have some warnings to review.',
OptimizerService.SummaryStatus.CompleteNeedsAttention => 'It looks like you have some errors to review.'
};

@AuraEnabled
public static Summary analyze() {
try {
OptimizerService.Summary summary = OptimizerService.analyize();
// Marshall into a response the Aura serializer supports
Summary responseSummary = new Summary();
responseSummary.severity = mapSummaryStatusToUIServerity.get(summary.Status);
responseSummary.title = mapSummaryStatusToUITitle.get(summary.Status);
responseSummary.message = mapSummaryStatusToUIMessage.get(summary.Status);
responseSummary.notifications = new List<Notification>();
for(OptimizerService.Notification notification : summary.Notifications.values()) {
Notification responseNotification = new Notification();
responseNotification.id = notification.Id.name();
responseNotification.severity = mapNotificationStatusToUIServerity.get(notification.Status);
responseNotification.message = notification.Message;
responseSummary.notifications.add(responseNotification);
}
return responseSummary;
} catch (Exception e) {
// Marshall into an exception the Aura serializer supports
throw new AuraHandledException(e.getMessage());
}
}

public class Summary {
@AuraEnabled
public String severity;
@AuraEnabled
public String title;
@AuraEnabled
public String message;
@AuraEnabled
public List<Notification> notifications;
}

public class Notification {
@AuraEnabled
public String id;
@AuraEnabled
public String severity;
@AuraEnabled
public String message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="urn:metadata.tooling.soap.sforce.com" fqn="OptimizerComponentController">
<apiVersion>42.0</apiVersion>
<status>Active</status>
</ApexClass>
143 changes: 143 additions & 0 deletions force-app/main/classes/OptimizerService.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* Copyright (c), Andrew Fawcett
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Andrew Fawcett, nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

/**
* Performs various health checks to keeping the tool running in tip top shape!
**/
global with sharing class OptimizerService {

/**
* Run all know checks
**/
global static Summary analyize() {
return analyize(new Set<NotificationReference>(NotificationReference.values()));
}

/**
* Run specified checks
**/
global static Summary analyize(Set<NotificationReference> checksToRun) {
Summary summary = new Summary();
summary.Notifications = new Map<NotificationReference, Notification>();
for(NotificationReference ref : checksToRun) {
// Look for an inner class in the service implementing the check
Type checkType = Type.forName(OptimizerService.class+'.'+ref.name());
if(checkType!=null) {
OptimizationCheckRunner check = (OptimizationCheckRunner) checkType.newInstance();
try {
// Run the optimization check
Notification notification = check.execute();
if(notification!=null) {
// Return the notiifcation for this check
summary.Notifications.put(ref, notification);
// Summary status reflects the most significant notificaiton status
if(notification.Status == NotificationStatus.Warning && summary.Status != SummaryStatus.CompleteNeedsAttention) {
summary.Status = SummaryStatus.CompleteWithWarnings;
} else if(notification.Status == NotificationStatus.Attention) {
summary.Status = SummaryStatus.CompleteNeedsAttention;
}
}
} catch (Exception e) {
// Return a failed notification notification!
Notification failedCheck = new Notification();
failedCheck.Status = NotificationStatus.CheckFailed;
failedCheck.Message = 'Optimization check ' + ref + ' failed to complete: ' + e.getMessage();
failedCheck.MoreInfoURL = null;
summary.Notifications.put(ref, failedCheck);
summary.Status = SummaryStatus.CompleteNeedsAttention;
}
}
}
if(summary.Status==null) {
summary.Status = SummaryStatus.Complete;
}
return summary;
}

/**
* Results of the optimizer analysis
**/
global class Summary {
global SummaryStatus Status {get; private set;}
global Map<NotificationReference, Notification> Notifications {get; private set;}
}

/**
* Notification to the user from a given analysis
**/
global class Notification {
global NotificationReference Id {get; private set;}
global NotificationStatus Status {get; private set;}
global String Message {get; private set;}
global String MoreInfoURL {get; private set;}
}

/**
* Status of the optimizer analysis (in future this may require background processing)
**/
global enum SummaryStatus {
Complete,
CompleteWithWarnings,
CompleteNeedsAttention
}

global enum NotificationStatus {
CheckFailed,
Warning,
Attention
}

/**
* Known optimization notications this service can return, use .values() to enumerate
**/
global enum NotificationReference {
LookupRollupSummaryLogsExist,
LookupRollupSummaryScheduleItemsInError,
LookupShadowRecordsNeedDeleting,
LookupRollupSummaryScheduleItemsFieldDeletion,
LookupRollupSummaryScheduleItemsWithFullCalcScheduleJob
}

/**
* Notifies the user if they have some records in the LookupRollupSummaryLogs__c record
**/
public class LookupRollupSummaryLogsExist extends OptimizationCheckRunner {
public override Notification execute() {
Notification notification = new Notification();
notification.Id = NotificationReference.LookupRollupSummaryLogsExist;
notification.Status = NotificationStatus.Warning;
notification.Message = 'Check the Lookup Rollup Summary Log tab for errors updating rollups.';
return notification;
}
}

/**
* Ability to run a optimization check
**/
public abstract class OptimizationCheckRunner {
public abstract Notification execute();
}
}
5 changes: 5 additions & 0 deletions force-app/main/classes/OptimizerService.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="urn:metadata.tooling.soap.sforce.com" fqn="OptimizerService">
<apiVersion>42.0</apiVersion>
<status>Active</status>
</ApexClass>
Loading

0 comments on commit 6571ab1

Please sign in to comment.