Enable/Disable Process Builder Processes all at once
I wrote a lightning component to allow me to easily enable and disable flows en masse.
It lists all the latest Flows, and give you buttons to:
- Toggle Selected Flows
- Enable All Flows
- Disable All Flows
Component
<aura:component controller="FlowManagerController" implements="flexipage:availableForAllPageTypes">
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:attribute name="flows" type="Object"/>
<aura:attribute name="selectedFlows" type="List"/>
<aura:attribute name="columns" type="List" default="[
{label: 'Developer Name', fieldName: 'DeveloperName', initialWidth: 500, type: 'text' },
{label: 'Active', fieldName: 'Active', initialWidth: 150, type: 'boolean'},
{label: 'Action', type: 'button', initialWidth: 200, typeAttributes:
{label: 'Change Status', name: 'change_status' }},
{label: 'Latest Version', fieldName: 'LatestVersionNumber', initialWidth: 150, type: 'number' },
{label: 'Active Version', fieldName: 'ActiveVersionNumber', initialWidth: 150, type: 'number' },
]" />
<aura:attribute name="loading" type="Boolean" default="false"/>
<aura:if isTrue="{!v.loading}">
<lightning:spinner alternativeText="Loading" size="large" />
</aura:if>
<div class="slds-card slds-p-around_small">
<div class="slds-p-bottom_small">
<lightning:button
label="Toggle selected Flows"
variant="brand"
onclick="{! c.handleToggleSelectedFlows }"
/>
<lightning:button
label="Enable All Flows"
variant="brand"
onclick="{! c.handleEnableAllFlows }"
/>
<lightning:button
label="Disable All Flows"
variant="brand"
onclick="{! c.handleDisableAllFlows }"
/>
</div>
<lightning:datatable keyField="id"
data="{! v.flows }"
onrowaction="{! c.handleRowAction }"
columns="{! v.columns }"
onrowselection="{! c.handleRowSelection }"
showRowNumberColumn="true" />
</div>
</aura:component>
JavaScript Controller
({
doInit : function(cmp, event, helper) {
helper.getFlows(cmp);
},
handleToggleSelectedFlows : function(cmp, event, helper){
helper.showLoading(cmp);
let flows = cmp.get("v.selectedFlows");
console.log(flows);
if (flows && flows.length > 0){
let promises = [];
flows.forEach(function(row) {
promises.push(helper.updateFlowPromise(cmp, row));
});
Promise.all(promises).then(function(results){
console.log(results);
helper.getFlows(cmp);
helper.hideLoading(cmp);
});
}
},
handleEnableAllFlows : function(cmp, event, helper){
helper.showLoading(cmp);
let flows = cmp.get("v.flows");
if (flows && flows.length > 0){
let promises = [];
flows.forEach(function(row){
if (row.Active == false) promises.push(helper.updateFlowPromise(cmp, row));
});
Promise.all(promises).then(function(results){
console.log(results);
helper.getFlows(cmp);
helper.hideLoading(cmp);
});
}
},
handleDisableAllFlows : function(cmp, event, helper){
helper.showLoading(cmp);
let flows = cmp.get("v.flows");
if (flows && flows.length > 0){
let promises = [];
flows.forEach(function(row) {
if (row.Active) promises.push(helper.updateFlowPromise(cmp, row));
});
Promise.all(promises).then(function(results){
console.log(results);
helper.getFlows(cmp);
helper.hideLoading(cmp);
});
}
},
handleRowSelection : function(cmp, event, helper){
let flows = event.getParam('selectedRows');
console.log(flows);
cmp.set("v.selectedFlows", flows);
},
handleRowAction: function(cmp, event, helper) {
var action = event.getParam('action');
if (action.name =='change_status') {
var row = event.getParam('row');
console.log(row);
helper.updateFlow(cmp, row);
}
}
})
JavaScript Helper
({
showLoading : function(cmp){
cmp.set("v.loading", true);
},
hideLoading : function(cmp){
cmp.set("v.loading", false);
},
getFlows : function(cmp) {
this.callAction(cmp, 'c.getFlows', null, function(results) {
if (results == null) return;
let data = JSON.parse(results);
let records = data.records;
if (records && records.length > 0) {
records.forEach(function(r){
if (r.ActiveVersion){
r.ActiveVersionNumber = r.ActiveVersion.VersionNumber;
r.Active = true;
} else {
r.ActiveVersionNumber = null;
r.Active = false;
}
r.LatestVersionNumber = r.LatestVersion.VersionNumber;
});
}
cmp.set("v.flows", records);
});
},
updateFlow : function(cmp, row){
let self = this;
let params = this.getParams(row);
this.callAction(cmp, 'c.updateFlow', params, function(result){
console.log(result);
if (result == true) self.getFlows(cmp);
})
},
updateFlowPromise : function(cmp, row){
let params = this.getParams(row);
return this.promiseAction(cmp, 'c.updateFlow', params);
},
getParams : function(row){
let flowId = row.Id;
let versionNumber = row.LatestVersionNumber;
if (row.Active) versionNumber = null;
let metadata = {
'Metadata': {
'activeVersionNumber': versionNumber
}
}
let params = {};
params.flowId = flowId;
params.metadata = JSON.stringify(metadata);
return params;
},
promiseAction : function(cmp, methodName, params){
console.log(methodName);
console.log(params);
var self = this;
return new Promise(function(resolve, reject) {
var action = cmp.get(methodName);
if (params != null) action.setParams(params);
action.setCallback(this, function(response) {
var state = response.getState();
console.log(methodName + ' ' + state);
if(cmp.isValid() && state === "SUCCESS"){
var result = response.getReturnValue();
//console.log(result);
resolve(result);
} else if (state === "ERROR"){
var errors = response.getError();
self.handleErrors(errors);
reject(errors);
}
});
$A.getCallback(function() {
$A.enqueueAction(action);
})();
});
},
callAction : function(cmp, methodName, params, callback){
var self = this;
var action = cmp.get(methodName);
if (params != null) action.setParams(params);
action.setCallback(this, function(response) {
var state = response.getState();
console.log(methodName + ' ' + state);
if(cmp.isValid() && state === "SUCCESS"){
var result = response.getReturnValue();
//console.log(result);
if (callback) callback(result);
} else if (state === "ERROR"){
self.handleErrors(response.getError());
}
});
$A.getCallback(function() {
$A.enqueueAction(action);
})();
},
handleErrors : function(errors) {
// Configure error toast
let toastParams = {
title: "Error",
message: "Unknown error", // Default error message
type: "error"
};
// use the error message if any
if (errors) {
if (errors[0] && errors[0].message) {
console.log(errors[0].message);
toastParams.message = errors[0].message;
}
}
// Fire error toast
let toastEvent = $A.get("e.force:showToast");
toastEvent.setParams(toastParams);
toastEvent.fire();
},
})
Apex Controller
public class FlowManagerController {
private static final string RESOURCE_TOOLING_QUERY_FLOW = '/tooling/query?q=Select+Id,ActiveVersion.VersionNumber,LatestVersion.VersionNumber,DeveloperName+From+FlowDefinition+ORDER+BY+DeveloperName';
private static final string RESOURCE_TOOLING_SOBJECT_FLOW = '/tooling/sobjects/FlowDefinition/';
@AuraEnabled
public static String getFlows() {
HttpResponse response = executeCallout('GET', RESOURCE_TOOLING_QUERY_FLOW, null);
System.debug(response);
if (response.getStatusCode() == 200) {
return response.getBody();
}
throw new AuraHandledException(response.toString());
}
@AuraEnabled
public static boolean updateFlow(String flowId, String metadata) {
HttpResponse response = executeCallout('PATCH', RESOURCE_TOOLING_SOBJECT_FLOW + flowId + '/?_HttpMethod=PATCH', metadata);
System.debug(response);
if (response.getStatusCode() == 200 || response.getStatusCode() == 204) {
return true;
}
return false;
}
public static HttpResponse executeCallout(String method, String resourceName, String requestBody) {
HttpRequest request = new HttpRequest();
if (method == 'PATCH') {
request.setMethod('POST');
} else {
request.setMethod(method);
}
request.setEndpoint(getUrl() + resourceName);
request.setHeader('Authorization', 'OAuth {!$Credential.OAuthToken}');
request.setHeader('Accept', 'application/json');
request.setHeader('X-PrettyPrint', '1');
request.setHeader('Content-Type', 'application/json');
if (String.isNotBlank(requestBody)) {
request.setBody(requestBody);
}
System.debug(request);
return new Http().send(request);
}
private static String getUrl(){
return 'callout:Named_Credential'; // CHANGE THIS
}
}
SETUP
- Create Connected App
- Create Auth. Provider
- Create Named Credential
- Create Lightning App Page called
Flow Manager