Skip to content

Commit

Permalink
Merge pull request #154 from SFDO-Community/feature/multi-match
Browse files Browse the repository at this point in the history
Feature/multi match
  • Loading branch information
tschug authored Jan 9, 2024
2 parents 02c80a0 + e2914c8 commit 4d620fc
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 61 deletions.
1 change: 1 addition & 0 deletions force-app/main/default/classes/Cmdt.cls
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public with sharing class Cmdt {
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,
Expand Down
4 changes: 4 additions & 0 deletions force-app/main/default/classes/IndicatorController.cls
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public with sharing class IndicatorController {
public class IndicatorItem {
@AuraEnabled
public Boolean IsActive {get; set;}
@AuraEnabled
public Boolean DisplayMultiple {get; set;}
@AuraEnabled
public String FieldLabel { get; set;}
@AuraEnabled
Expand Down Expand Up @@ -186,6 +188,7 @@ public with sharing class IndicatorController {
}

item.IsActive = indicatorItem.Active__c;
item.DisplayMultiple = indicatorItem.Display_Multiple__c;
item.IconName = indicatorItem.Icon_Value__c;
item.TextValue = indicatorItem.Static_Text__c;
item.EmptyStaticBehavior = indicatorItem.Empty_Static_Text_Behavior__c;
Expand Down Expand Up @@ -285,6 +288,7 @@ public with sharing class IndicatorController {
}

item.IsActive = indicatorItem.Active__c;
item.DisplayMultiple = indicatorItem.Display_Multiple__c;
item.IconName = indicatorItem.Icon_Value__c;
item.TextValue = indicatorItem.Static_Text__c;
item.EmptyStaticBehavior = indicatorItem.Empty_Static_Text_Behavior__c;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
<label>Configuration</label>
<layoutColumns>
<layoutItems>
<emptySpace>true</emptySpace>
<behavior>Edit</behavior>
<field>Display_Multiple__c</field>
</layoutItems>
<layoutItems>
<behavior>Edit</behavior>
Expand Down
145 changes: 86 additions & 59 deletions force-app/main/default/lwc/indicatorBundle/indicatorBundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export default class IndicatorBundle extends LightningElement {
this.bundle.Items.forEach(
item =>
{
let anyMatch = false;
if(item.IsActive){

// console.dir(item); // Retain for debug purposes
Expand Down Expand Up @@ -249,7 +250,7 @@ export default class IndicatorBundle extends LightningElement {

// console.log('Match Status', match); // Retain for debug purposes
if(match) {
// If there is a match for an Extension, assign the extension's override values
// If there is a match for an Extension, assign the extension's override values and these will be used later
matchedExtension = {
"IconName" : extension.ExtensionIconValue,
"TextValue" : extension.ExtensionTextValue,
Expand All @@ -259,76 +260,102 @@ export default class IndicatorBundle extends LightningElement {
"IconBackground" : extension.BackgroundColor,
"IconForeground" : extension.ForegroundColor
};

// However, if multiple matching is enabled, immediately assign the Extension for use in the Bundle.
if(item.DisplayMultiple){
anyMatch = true;
matchingFields.push(
{
fName: item.FieldApiName,
fTextValue: dataValue,
fImageURL: matchedExtension.ImageUrl,
fHoverValue: (matchedExtension && matchedExtension.HoverValue) ? matchedExtension.HoverValue : assignedHoverValue,
fShowAvatar: true,
fIconName : matchedExtension.IconName,
fIconBackground : matchedExtension.IconBackground,
fIconForeground : matchedExtension.IconForeground,
fTextShown: matchedExtension.TextValue
}
);
}

// console.dir(matchedExtension);
}
} // End-If extension.IsActive
}

)

}

matchingFields.push(
{
fName: item.FieldApiName, // Retain for debug purposes
fTextValue: dataValue, // Retain for debug purposes
...dataValue || dataValue === 0 ? {
fImageURL: matchedExtension ? matchedExtension.ImageUrl : item.ImageUrl
} : {
fImageURL: item.DisplayFalse ? item.FalseImageUrl : ''
},
// ! If value is false, the false hover will be set.
...dataValue || dataValue === 0 ? {
fHoverValue: (matchedExtension && matchedExtension.HoverValue) ? matchedExtension.HoverValue : assignedHoverValue
} : {
fHoverValue: item.DisplayFalse ? item.FalseHoverValue : ''
},
//If False Icon is not entered AND the boolean value is False or text value is empty, then do not display the Avatar
...dataValue || dataValue === 0 ? {
fShowAvatar : matchedExtension ? true : showDefault
} : {
fShowAvatar: item.DisplayFalse
},
//If the value is false, the false icon will be set.
...dataValue || dataValue === 0 ? {
fIconName : matchedExtension ? matchedExtension.IconName : item.IconName
} : {
fIconName: item.DisplayFalse ? item.FalseIcon : ''
},
...dataValue || dataValue === 0 ? {
fIconBackground : matchedExtension ? matchedExtension.IconBackground : item.BackgroundColor
} : {
fIconBackground: item.DisplayFalse? item.InverseBackgroundColor : item.BackgroundColor
},
...dataValue || dataValue === 0 ? {
fIconForeground : matchedExtension ? matchedExtension.IconForeground : item.ForegroundColor
} : {
fIconForeground: item.DisplayFalse? item.InverseForegroundColor : item.ForegroundColor
},
//If the False Icon and False Text is entered and the Boolean is False or text value is empty, then set the False Text
//If the Icon Text is entered then show that
//If no Icon Text is entered if the field is a Boolean then show the icon otherwise show the field value
...dataValue || dataValue === 0 ? {
...matchedExtension ? {
fTextShown: matchedExtension.TextValue ? matchedExtension.TextValue.toUpperCase().substring(0,3) : ''

// If multiple matching is enabled and did not find a single match
// or if multiple matching is not enabled
// proceed to assign the indicator properties based on Indicator Item values
if (anyMatch != true || item.DisplayMultiple != true) {

matchingFields.push(
{
fName: item.FieldApiName, // Retain for debug purposes
fTextValue: dataValue, // Retain for debug purposes
...dataValue || dataValue === 0 ? {
fImageURL: matchedExtension ? matchedExtension.ImageUrl : item.ImageUrl
} : {
fImageURL: item.DisplayFalse ? item.FalseImageUrl : ''
},
// ! If value is false, the false hover will be set.
...dataValue || dataValue === 0 ? {
fHoverValue: (matchedExtension && matchedExtension.HoverValue) ? matchedExtension.HoverValue : assignedHoverValue
} : {
fHoverValue: item.DisplayFalse ? item.FalseHoverValue : ''
},
//If False Icon is not entered AND the boolean value is False or text value is empty, then do not display the Avatar
...dataValue || dataValue === 0 ? {
fShowAvatar : matchedExtension ? true : showDefault
} : {
fShowAvatar: item.DisplayFalse
},
//If the value is false, the false icon will be set.
...dataValue || dataValue === 0 ? {
fIconName : matchedExtension ? matchedExtension.IconName : item.IconName
} : {
fIconName: item.DisplayFalse ? item.FalseIcon : ''
},
...dataValue || dataValue === 0 ? {
fIconBackground : matchedExtension ? matchedExtension.IconBackground : item.BackgroundColor
} : {
...dataValue && item.TextValue ? {
fTextShown : item.TextValue.toUpperCase().substring(0,3)
fIconBackground: item.DisplayFalse? item.InverseBackgroundColor : item.BackgroundColor
},
...dataValue || dataValue === 0 ? {
fIconForeground : matchedExtension ? matchedExtension.IconForeground : item.ForegroundColor
} : {
fIconForeground: item.DisplayFalse? item.InverseForegroundColor : item.ForegroundColor
},
//If the False Icon and False Text is entered and the Boolean is False or text value is empty, then set the False Text
//If the Icon Text is entered then show that
//If no Icon Text is entered if the field is a Boolean then show the icon otherwise show the field value
...dataValue || dataValue === 0 ? {
...matchedExtension ? {
fTextShown: matchedExtension.TextValue ? matchedExtension.TextValue.toUpperCase().substring(0,3) : ''
} : {
...item.EmptyStaticBehavior === 'Use Icon Only' ? {
fTextShown : ''
} : {
fTextShown : typeof(dataValue) === 'boolean' ? '' : String(dataValue).toUpperCase().substring(0,3)
}
...dataValue && item.TextValue ? {
fTextShown : item.TextValue.toUpperCase().substring(0,3)
} : {
...item.EmptyStaticBehavior === 'Use Icon Only' ? {
fTextShown : ''
} : {
fTextShown : typeof(dataValue) === 'boolean' ? '' : String(dataValue).toUpperCase().substring(0,3)
}
}
}
}
} : {
...(dataValue === false || dataValue === null || dataValue === '') && item.DisplayFalse ? {
fTextShown : item.FalseTextValue ? item.FalseTextValue.toUpperCase().substring(0,3) : ''
} : {
fTextShown : ''
...(dataValue === false || dataValue === null || dataValue === '') && item.DisplayFalse ? {
fTextShown : item.FalseTextValue ? item.FalseTextValue.toUpperCase().substring(0,3) : ''
} : {
fTextShown : ''
}
}
}
});
});
}
} // End-If item.IsActive
});
this.results = matchingFields;
Expand Down
11 changes: 10 additions & 1 deletion force-app/main/default/lwc/key/key.html
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,16 @@ <h2>Item is not active. No indicators will be shown, even if they are active.</
</span>
</lightning-layout-item>
<lightning-layout-item padding="around-small" size="2" class="slds-border_bottom">
<b>Display Criteria</b>
<b>Display Criteria </b>
<template lwc:if={indicatorItem.DisplayMultiple}>
<span style="position:relative; top:-4px;">
<lightning-helptext
icon-name="utility:tile_card_list"
alternative-text="Display Multiple Enabled"
icon-variant="warning"
content="Display Multiple has been enabled. Any criteria met will display that indicator."></lightning-helptext>
</span>
</template>
</lightning-layout-item>
<template lwc:if={isManageEnabled}>
<lightning-layout-item padding="around-small" size="1" class="slds-border_bottom">
Expand Down
1 change: 1 addition & 0 deletions force-app/main/default/lwc/key/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ export default class Key extends LightningElement {
DisplayFalse: item.DisplayFalse,
ZeroValueMode: item.ZeroBehavior ? item.ZeroBehavior : '',
DisplayZero: item.ZeroBehavior ? true : false,
DisplayMultiple: item.DisplayMultiple,
Description: item.IndicatorDescription,
IndicatorId: item.IndicatorId,
Indicators: indicators,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Display_Multiple__c</fullName>
<defaultValue>false</defaultValue>
<externalId>false</externalId>
<fieldManageability>SubscriberControlled</fieldManageability>
<inlineHelpText>Display multiple Extensions when matched, helpful with multi-select picklists.</inlineHelpText>
<label>Display Multiple</label>
<type>Checkbox</type>
</CustomField>
50 changes: 50 additions & 0 deletions unpackaged/notes/developer_notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Developer Notes

These notes are for developers to track specific items for the Indicators project.

## AppExchange Security Review

More details can be found [here](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_guidelines.htm).

## Checkmarx

This should be run through a Salesforce/SFDO employee.

## Salesforce Code Analyzer (Code Scanner)

When making any changes to Apex code, always run the code scanner to find any areas of concern.

More details can be found [here](https://forcedotcom.github.io/sfdx-scanner/).

Specifically, we run the following to commands:

```
sf scanner run --format=csv --outfile=CodeAnalyzerGeneral.csv --target="./" --category="Security"
```

And we run an exclusion DFA scan

```
sf scanner run dfa --format=csv --outfile=CodeAnalyzerDFA.csv --target ".\**\*.cls,!.\**\IndicatorController.cls" --projectdir="./force-app/" --category="Security"
```

> This will run for all `.cls` files except for the `IndicatorController.cls` because it takes too long to scan.
>
> Note: We have specifically limited the command (`scanner run dfa`) to the `force-app` directory. This is because the `%` character used with CCI (and within NPSP) throws errors.
Then we run

```
sf scanner run dfa --format=csv --outfile=CodeAnalyzerDFA_1.csv --target="./force-app/main/default/classes/IndicatorController.cls#getNewCmdtUrls" --projectdir="./force-app" --category="Security"
```

> We needed the additional commands to specific methods in the `IndicatorController.cls` file because the command (`scanner run dfa`) runs for a longer time than the command (`scanner run`).
And finally, we run
```
sf scanner run dfa --sfgejvmargs "-Xmx5g" --format=csv --outfile=CodeAnalyzerDFA_2.csv --target="./force-app/main/default/classes/IndicatorController.cls#getIndicatorBundle" --projectdir="./force-app" --category="Security"
```

> It's possible to hit an Out-of-Memory error, in which case it requires [increasing the Java heap space](https://forcedotcom.github.io/sfdx-scanner/en/v3.x/salesforce-graph-engine/working-with-sfge/#understand-limitreached-errors) or even [setting the target to multple files](https://forcedotcom.github.io/sfdx-scanner/en/v3.x/scanner-commands/dfa/).
📢 When the CCI design comes more aggressive, it is likely that we will need to scan the `unpackaged` directory too.

0 comments on commit 4d620fc

Please sign in to comment.