diff --git a/force-app/main/default/classes/Cmdt.cls b/force-app/main/default/classes/Cmdt.cls index ff52300..c8122a9 100644 --- a/force-app/main/default/classes/Cmdt.cls +++ b/force-app/main/default/classes/Cmdt.cls @@ -5,18 +5,19 @@ public with sharing class Cmdt { // Gather all active Bundles and put them into a Map (key: DeveloperName; Bundle) for( Indicator_Bundle__mdt bundle : [ - SELECT Id, DeveloperName, MasterLabel, Label, - Active__c, - Card_Icon__c, - Card_Icon_Background__c, - Card_Icon_Foreground__c, - Card_Text__c, - Card_Title__c, - Description__c, - sObject__c, - sObject__r.QualifiedApiName, - sObject__r.Label - FROM Indicator_Bundle__mdt + SELECT Id, DeveloperName, MasterLabel, Label, QualifiedApiName, + Active__c, + Card_Icon__c, + Card_Icon_Background__c, + Card_Icon_Foreground__c, + Card_Text__c, + Card_Title__c, + Description__c, + sObject__c, + sObject__r.QualifiedApiName, + sObject__r.Label + FROM Indicator_Bundle__mdt + WHERE Delete__c != TRUE ] ) { setBundle(bundle); } @@ -24,31 +25,32 @@ public with sharing class Cmdt { // Gather all active Items and put them into a Map (key: Developername; Item) // Using SOQL because of parent-related values AND Advanced_Field__c is long text. for( Indicator_Item__mdt item : [ - SELECT Id, DeveloperName, MasterLabel, - Active__c, - Advanced_Field__c, - Advanced_Field_Label__c, - Display_Multiple__c, - Empty_Static_Text_Behavior__c, - Field__c, Field__r.QualifiedApiName, - Hover_Text__c, - Icon_Value__c, - Image__c, - Inverse_Hover_Text__c, - Inverse_Icon_Value__c, - Inverse_Image__c, - Inverse_Static_Text__c, - Show_False_or_Blank__c, - sObject__c, sObject__r.QualifiedApiName, - Static_Text__c, - Zero_Behavior__c, - Icon_Background__c, - Icon_Foreground__c, - Inverse_Icon_Background__c, - Inverse_Icon_Foreground__c, - Description__c - FROM Indicator_Item__mdt - // WHERE Active__c = TRUE + SELECT Id, DeveloperName, MasterLabel, Label, QualifiedApiName, + Active__c, + Advanced_Field__c, + Advanced_Field_Label__c, + Display_Multiple__c, + Empty_Static_Text_Behavior__c, + Field__c, Field__r.QualifiedApiName, + Hover_Text__c, + Icon_Value__c, + Image__c, + Inverse_Hover_Text__c, + Inverse_Icon_Value__c, + Inverse_Image__c, + Inverse_Static_Text__c, + Show_False_or_Blank__c, + sObject__c, sObject__r.QualifiedApiName, + Static_Text__c, + Zero_Behavior__c, + Icon_Background__c, + Icon_Foreground__c, + Inverse_Icon_Background__c, + Inverse_Icon_Foreground__c, + Description__c + FROM Indicator_Item__mdt + WHERE Delete__c != TRUE + // WHERE Active__c = TRUE ]){ setItem(item); } @@ -56,13 +58,15 @@ public with sharing class Cmdt { // Gather all active Bundle Items (Bundle and Item are active) and put them into a Map (key: Bundle DeveloperName; List of BundleItems) // Using SOQL because of the Order By clause rather than creating a custom sort method. for( Indicator_Bundle_Item__mdt bundleItem : [ - SELECT Indicator_Bundle__c, Indicator_Bundle__r.DeveloperName, - Indicator_Item__c, Indicator_Item__r.DeveloperName, - Order__c - FROM Indicator_Bundle_Item__mdt - // WHERE Indicator_Bundle__r.Active__c = TRUE - // AND Indicator_Item__r.Active__c = TRUE - ORDER BY Order__c + SELECT Id, DeveloperName, QualifiedApiName, MasterLabel, Label, + Indicator_Bundle__c, Indicator_Bundle__r.DeveloperName, Indicator_Bundle__r.QualifiedApiName, + Indicator_Item__c, Indicator_Item__r.DeveloperName, Indicator_Item__r.QualifiedApiName, + Order__c + FROM Indicator_Bundle_Item__mdt + WHERE Delete__c != TRUE + // WHERE Indicator_Bundle__r.Active__c = TRUE + // AND Indicator_Item__r.Active__c = TRUE + ORDER BY Order__c ]){ setBundleItem(bundleItem); } @@ -70,25 +74,28 @@ public with sharing class Cmdt { // Gather all active Item Extensions and put them into a Map (key: Indicator Item; List of Extensions) // Using SOQL because of the Order By clause rather than creating a custom sort method. for(Indicator_Item_Extension__mdt itemExtension : [ - SELECT Id, Active__c, - Contains_Text__c, - Text_Operator__c, - Hover_Text__c, - Icon_Value__c, - Image__c, - Indicator_Item__c, - Indicator_Item__r.DeveloperName, - Maximum__c, - Minimum__c, - Priority__c, - Static_Text__c, - Icon_Background__c, - Icon_Foreground__c, - Description__c - FROM Indicator_Item_Extension__mdt - // WHERE Active__c = TRUE - // AND Indicator_Item__r.Active__c = TRUE - ORDER BY Indicator_Item__c, Priority__c DESC, MasterLabel + SELECT Id, DeveloperName, QualifiedApiName, Label, MasterLabel, + Active__c, + Contains_Text__c, + Text_Operator__c, + Hover_Text__c, + Icon_Value__c, + Image__c, + Indicator_Item__c, + Indicator_Item__r.DeveloperName, + Indicator_Item__r.QualifiedApiName, + Maximum__c, + Minimum__c, + Priority__c, + Static_Text__c, + Icon_Background__c, + Icon_Foreground__c, + Description__c + FROM Indicator_Item_Extension__mdt + WHERE Delete__c != TRUE + // WHERE Active__c = TRUE + // AND Indicator_Item__r.Active__c = TRUE + ORDER BY Indicator_Item__c, Priority__c DESC, MasterLabel ]){ setItemExtension(itemExtension); } @@ -143,7 +150,7 @@ public with sharing class Cmdt { } public static List getAllOrphanItems(){ - + List orphanItems = new List(); for(String itemName : itemsByName.keyset()){ @@ -159,28 +166,28 @@ public with sharing class Cmdt { if(bundlesByName.containsKey(bundleDevName)) return bundlesByName.get(bundleDevName); else - return new Indicator_Bundle__mdt(); + return new Indicator_Bundle__mdt(); } public static Indicator_Item__mdt getItem(String itemDevName){ if(itemsByName.containsKey(itemDevName)) return itemsByName.get(itemDevName); else - return new Indicator_Item__mdt(); + return new Indicator_Item__mdt(); } public static List getBundleItems(String bundleDevName){ if(bundleItemsByBundle.containsKey(bundleDevname)) return bundleItemsByBundle.get(bundleDevName); - else - return new List(); + else + return new List(); } public static List getExtensionsForItem(String itemDevName){ if(extensionsByItem.containsKey(itemDevName)) return extensionsByItem.get(itemDevName); else - return new List(); + return new List(); } // Static variables used across methods. diff --git a/force-app/main/default/classes/MetadataDeploy.cls b/force-app/main/default/classes/MetadataDeploy.cls new file mode 100644 index 0000000..105b2c4 --- /dev/null +++ b/force-app/main/default/classes/MetadataDeploy.cls @@ -0,0 +1,23 @@ +/** + * Created by robertwright on 10/30/23. + */ + +public with sharing class MetadataDeploy implements Metadata.DeployCallback { + + public String resultMessage; + + public void handleResult(Metadata.DeployResult result,Metadata.DeployCallbackContext context) { + if(result.status === Metadata.DeployStatus.Succeeded) { + resultMessage = 'MetaData Deploy Succeeded'; + } else resultMessage = 'MetaData Deploy Failed'; + if(Test.isRunningTest()) System.debug(resultMessage); + } + + public static Id upsertMetaData(Metadata.DeployContainer deployContainer) { + MetadataDeploy callback = new MetadataDeploy(); + Id upsertId; + if(!Test.isRunningTest()) upsertId = Metadata.Operations.enqueueDeployment(deployContainer,callback); + return upsertId; + } + +} \ No newline at end of file diff --git a/force-app/main/default/classes/MetadataDeploy.cls-meta.xml b/force-app/main/default/classes/MetadataDeploy.cls-meta.xml new file mode 100644 index 0000000..7a51829 --- /dev/null +++ b/force-app/main/default/classes/MetadataDeploy.cls-meta.xml @@ -0,0 +1,5 @@ + + + 58.0 + Active + diff --git a/force-app/main/default/classes/MetadataDeployTests.cls b/force-app/main/default/classes/MetadataDeployTests.cls new file mode 100644 index 0000000..1131fc6 --- /dev/null +++ b/force-app/main/default/classes/MetadataDeployTests.cls @@ -0,0 +1,10 @@ +/** + * Created by robertwright on 10/30/23. + */ + +@IsTest +private class MetadataDeployTests { + @IsTest + static void testBehavior() { + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/MetadataDeployTests.cls-meta.xml b/force-app/main/default/classes/MetadataDeployTests.cls-meta.xml new file mode 100644 index 0000000..7a51829 --- /dev/null +++ b/force-app/main/default/classes/MetadataDeployTests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 58.0 + Active + diff --git a/force-app/main/default/classes/MetadataUtility.cls b/force-app/main/default/classes/MetadataUtility.cls new file mode 100644 index 0000000..26c1199 --- /dev/null +++ b/force-app/main/default/classes/MetadataUtility.cls @@ -0,0 +1,123 @@ +/** + * Created by robertwright on 10/30/23. + */ + +public with sharing class MetadataUtility { + + /**Static Params**/ + private static final String Label_Field = 'Label'; + private static final String QualifiedApiName_Field = 'QualifiedApiName'; + private static final Set entityRelationshipFields = new Set{ + Indicator_Bundle__mdt.sObject__c.getDescribe(), + Indicator_Item__mdt.Field__c.getDescribe(), + Indicator_Item__mdt.sObject__c.getDescribe() + }; + + private static Metadata.DeployContainer deployContainer; + private static DescribeSObjectResult describeSObjectResult; + private static Map populatedFieldsMap; + + /**Wrappers**/ + public class deploymentWrapper { + + @AuraEnabled public Indicator_Bundle__mdt indicatorBundle; + @AuraEnabled public List indicatorBundleItems; + @AuraEnabled public Indicator_Item__mdt indicatorItem; + @AuraEnabled public List indicatorItemExtensions; + + public deploymentWrapper() {} + + } + + /**Controller Methods**/ + @AuraEnabled + public static Id deployIndicatorBundles(deploymentWrapper items) { + return deployWrapperMetadata(items); + } + + /**Metadata Methods**/ + private static Id deployWrapperMetadata(deploymentWrapper wrapper) { + deployContainer = new Metadata.DeployContainer(); // Build New Deployment Container + if(wrapper.indicatorBundle != null) processMetadataRecords(new List{wrapper.indicatorBundle},Indicator_Bundle__mdt.getSObjectType()); + if(wrapper.indicatorItem != null) processMetadataRecords(new List{wrapper.indicatorItem},Indicator_Item__mdt.getSObjectType()); + if(wrapper.indicatorItemExtensions != null && !wrapper.indicatorItemExtensions.isEmpty()) processMetadataRecords(wrapper.indicatorItemExtensions,Indicator_Item_Extension__mdt.getSObjectType()); + if(wrapper.indicatorBundleItems != null && !wrapper.indicatorBundleItems.isEmpty()) processMetadataRecords(wrapper.indicatorBundleItems,Indicator_Bundle_Item__mdt.getSObjectType()); + Id deployId = MetadataDeploy.upsertMetaData(deployContainer); // Deploy Deploy Container + return deployId; + } + + private static void processMetadataRecords(List records,SObjectType sObjectType) { + describeSObjectResult = sObjectType.getDescribe(); + for(SObject record : records) buildMetaData(record.getPopulatedFieldsAsMap()); // Build Metadata Maps and Add to Deploy Container + } + + private static void buildMetaData(Map metadataFieldValueMap) { + populatedFieldsMap = metadataFieldValueMap; + if(populatedFieldsMap == null) populatedFieldsMap = new Map(); + + String sObjectName = describeSObjectResult.getName(); + String QualifiedApiName = (String) populatedFieldsMap.get(QualifiedApiName_Field); + String fullName = mergeFullName(sObjectName,QualifiedApiName); + String label = (String) populatedFieldsMap.get(Label_Field); + + if(String.isBlank(label)) label = 'Unnamed Metadata'; + Metadata.CustomMetadata customMetadata = buildCustomMetadata(fullName,label); + deployContainer.addMetadata(customMetadata); + } + + private static String mergeFullName(String metadataName, String QualifiedApiName) { + String DeveloperName = (QualifiedApiName.length() > 40) ? QualifiedApiName.substring(0,40) : QualifiedApiName; + return metadataName.replace('__mdt','')+'.'+DeveloperName; + } + + private static Metadata.CustomMetadata buildCustomMetadata(String fullName, String recordLabel) { + Metadata.CustomMetadata customMetadata = new Metadata.CustomMetadata(); + customMetadata.fullName = fullName; + customMetadata.label = (recordLabel.length() > 40) ? recordLabel.substring(0,40) : recordLabel; + + Map describeFieldMap = describeSObjectResult.fields.getMap(); + + for(String fieldName : populatedFieldsMap.keySet()) processCustomMetadataFieldValues(customMetadata,describeFieldMap.get(fieldName)); + + return customMetadata; + } + + private static void processCustomMetadataFieldValues(Metadata.CustomMetadata customMetadata,Schema.SObjectField sObjectField) { + + if(sObjectField == null) return; /**Return if sObjectField not found**/ + DescribeFieldResult fieldResult = sObjectField.getDescribe(); + if(!fieldResult.isCustom()) return; /**Return If Standard Field**/ + + String fieldName = fieldResult.getName(); + Boolean isReference = fieldResult.getType() === DisplayType.REFERENCE; + Boolean isEntityRelationshipField = entityRelationshipFields.contains(fieldResult); + + Object value = null; + + if(isReference || isEntityRelationshipField) { + SObject relatedRecord; + Map relatedRecordPopulatedFieldMap; + String relationshipName = (isEntityRelationshipField) ? fieldName.removeEnd('__c')+'__r' : fieldResult.getRelationshipName(); /**We replace __c with __r to resolve Entity Relationship non reference**/ + if(populatedFieldsMap.containsKey(relationshipName)) { + try{ + relatedRecord = (SObject) populatedFieldsMap.get(relationshipName); + relatedRecordPopulatedFieldMap = relatedRecord.getPopulatedFieldsAsMap(); + } catch(Exception ex) { + System.debug(ex.getMessage()); + } + } + if(relatedRecordPopulatedFieldMap != null && relatedRecordPopulatedFieldMap.containsKey(QualifiedApiName_Field)) value = (String) relatedRecordPopulatedFieldMap.get(QualifiedApiName_Field); + + } else if(populatedFieldsMap.containsKey(fieldName)) value = populatedFieldsMap.get(fieldName); + + if(value == null || value == '' && fieldResult.defaultValue != null) value = fieldResult.defaultValue; + else if(value == null || value == '' && fieldResult.defaultValueFormula != null) value = fieldResult.defaultValueFormula.removeEnd('\'').removeEnd('"').removeStart('\'').removeStart('"'); + + Metadata.CustomMetadataValue metadataField = new Metadata.CustomMetadataValue(); + metadataField.field = fieldName; + metadataField.value = value; + + customMetadata.values.add(metadataField); + } + +} \ No newline at end of file diff --git a/force-app/main/default/classes/MetadataUtility.cls-meta.xml b/force-app/main/default/classes/MetadataUtility.cls-meta.xml new file mode 100644 index 0000000..fbbad0a --- /dev/null +++ b/force-app/main/default/classes/MetadataUtility.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + diff --git a/force-app/main/default/lwc/configurationManager/configurationManager.html b/force-app/main/default/lwc/configurationManager/configurationManager.html index 0fd987e..79908ec 100644 --- a/force-app/main/default/lwc/configurationManager/configurationManager.html +++ b/force-app/main/default/lwc/configurationManager/configurationManager.html @@ -6,44 +6,45 @@

Review existing Indicators or create new custom metadata records.

- - - + + +