From 3c96d8ed889f60fb32cb430778df963ca4ca270f Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Tue, 31 Oct 2023 15:23:56 -0500 Subject: [PATCH 01/23] First build of indicator builder --- .../classes/ObjectFieldSelectorController.cls | 114 ++ ...ObjectFieldSelectorController.cls-meta.xml | 5 + .../ObjectFieldSelectorControllerTest.cls | 18 + ...ctFieldSelectorControllerTest.cls-meta.xml | 5 + .../default/lwc/fsc_combobox/fsc_combobox.css | 3 + .../lwc/fsc_combobox/fsc_combobox.html | 182 +++ .../default/lwc/fsc_combobox/fsc_combobox.js | 586 +++++++ .../lwc/fsc_combobox/fsc_combobox.js-meta.xml | 14 + .../fsc_comboboxUtils/fsc_comboboxUtils.js | 33 + .../fsc_comboboxUtils.js-meta.xml | 5 + .../fsc_fieldSelector2.html | 25 + .../fsc_fieldSelector2/fsc_fieldSelector2.js | 235 +++ .../fsc_fieldSelector2.js-meta.xml | 5 + .../fsc_objectFieldSelectorUtils.js | 58 + .../fsc_objectFieldSelectorUtils.js-meta.xml | 5 + .../fsc_objectSelector.html | 24 + .../fsc_objectSelector/fsc_objectSelector.js | 157 ++ .../fsc_objectSelector.js-meta.xml | 15 + .../lwc/iconSelector/iconSelector.html | 45 + .../default/lwc/iconSelector/iconSelector.js | 1406 +++++++++++++++++ .../lwc/iconSelector/iconSelector.js-meta.xml | 29 + .../__tests__/indicatorBuilder.test.js | 25 + .../lwc/indicatorBuilder/indicatorBuilder.css | 7 + .../indicatorBuilder/indicatorBuilder.html | 157 ++ .../lwc/indicatorBuilder/indicatorBuilder.js | 201 +++ .../indicatorBuilder.js-meta.xml | 8 + .../indicatorBundleItem.js | 83 +- 27 files changed, 3434 insertions(+), 16 deletions(-) create mode 100644 force-app/main/default/classes/ObjectFieldSelectorController.cls create mode 100644 force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml create mode 100644 force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls create mode 100644 force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.css create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.html create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.js create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js create mode 100644 force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html create mode 100644 force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js create mode 100644 force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html create mode 100644 force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js create mode 100644 force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml create mode 100644 force-app/main/default/lwc/iconSelector/iconSelector.html create mode 100644 force-app/main/default/lwc/iconSelector/iconSelector.js create mode 100644 force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml create mode 100644 force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml diff --git a/force-app/main/default/classes/ObjectFieldSelectorController.cls b/force-app/main/default/classes/ObjectFieldSelectorController.cls new file mode 100644 index 0000000..22b6aab --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorController.cls @@ -0,0 +1,114 @@ +public with sharing class ObjectFieldSelectorController { + + public static final String STANDARD = 'standard'; + public static final String SPECIFIC = 'specific'; + public static final String CUSTOM = 'custom'; + public static final String BOTH = 'both'; + public static final String ANCILLARY = 'ancillary'; + public static final String ALL = 'all'; + + @AuraEnabled + public static GetObjectsResult getObjects(String selectionType, List availableObjects) { + if (String.isBlank(selectionType)) + selectionType = BOTH; + selectionType = selectionType.toLowerCase(); + GetObjectsResult result = new GetObjectsResult(); + result.objects = new List(); + List describeResults = new List(); + if (selectionType == ALL) { + Map objMap = Schema.getGlobalDescribe(); + for (Schema.SObjectType objType : objMap.values()) { + describeResults.add(objType.getDescribe()); + } + } else if (selectionType == SPECIFIC) { + describeResults = Schema.describeSObjects(availableObjects); + } else { + List objectNames = new List(); + List entityDefs = new List(); + if (selectionType == STANDARD || selectionType == BOTH) { + entityDefs.addAll([SELECT KeyPrefix, QualifiedApiName, DeveloperName FROM EntityDefinition WHERE (NOT QualifiedApiName LIKE '%__c') AND (NOT QualifiedApiName LIKE '%Feed') AND (NOT QualifiedApiName LIKE '%Tag') AND (NOT QualifiedApiName LIKE '%Share') AND (NOT QualifiedApiName LIKE '%ChangeEvent') AND (NOT QualifiedApiName LIKE '%History')]); + } + if (selectionType == CUSTOM || selectionType == BOTH) { + entityDefs.addAll([SELECT QualifiedApiName FROM EntityDefinition WHERE QualifiedApiName LIKE '%__c']); + } + if (selectionType == ANCILLARY) { + entityDefs.addAll([SELECT QualifiedApiName, DeveloperName FROM EntityDefinition WHERE QualifiedApiName LIKE '%Feed' OR QualifiedApiName LIKE '%Tag' OR QualifiedApiName LIKE '%Share' OR QualifiedApiName LIKE '%ChangeEvent' OR QualifiedApiName LIKE '%History']); + } + for (EntityDefinition def : entityDefs) { + // The standard list of EntityDefinitions may still return some odd types like metadata, so we filter out any object with double underscores + if (selectionType != STANDARD || !def.QualifiedApiName.contains('__')) { + objectNames.add(def.QualifiedApiName); + } + } + describeResults = Schema.describeSObjects(objectNames); + } + for (Schema.DescribeSObjectResult res : describeResults) { + result.objects.add(new ObjectResult(res.getLabel(), res.getName())); + } + return result; + } + + @AuraEnabled(cacheable=true) + public static GetObjectFieldsResult getObjectFields(String objectName) { + GetObjectFieldsResult result = new GetObjectFieldsResult(); + result.fields = new List(); + try { + Map tokenMap = ((SObject)Type.forName('Schema', objectName).newInstance()).getSObjectType().getDescribe().fields.getMap(); + for (Schema.SObjectField objField : tokenMap.values()) { + FieldResult newField = new FieldResult(objField.getDescribe()); + System.debug(newField); + result.fields.add(newField); + } + } catch (Exception e) { + result.errorMessage = e.getMessage(); + return result; + } + System.debug('about to return result, with '+ result.fields.size() +' fields'); + return result; + } + + public class GetObjectsResult { + @AuraEnabled public List objects; + } + + public class ObjectResult { + @AuraEnabled public String label; + @AuraEnabled public String value; + + public ObjectResult(String label, String value) { + this.label = label; + this.value = value; + } + } + + public class GetObjectFieldsResult { + @AuraEnabled public String errorMessage; + @AuraEnabled public List fields; + } + + public class FieldResult { + @AuraEnabled public String apiName; + @AuraEnabled public String label; + @AuraEnabled public String dataType; + @AuraEnabled public List referenceToInfos; + + public FieldResult(Schema.DescribeFieldResult fieldResult) { + this.apiName = fieldResult.getName(); + this.label = fieldResult.getLabel(); + this.dataType = fieldResult.getType().name(); + List refToInfos = new List(); + for (Schema.sObjectType objType : fieldResult.getReferenceTo()) { + refToInfos.add(new ReferenceToInfo(objType.getDescribe().getName())); + } + this.referenceToInfos = refToInfos; + } + } + + public class ReferenceToInfo { + @AuraEnabled public String apiName; + + public ReferenceToInfo(String apiName) { + this.apiName = apiName; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml b/force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml new file mode 100644 index 0000000..40d6793 --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls new file mode 100644 index 0000000..76fcfd9 --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls @@ -0,0 +1,18 @@ +@isTest +public class ObjectFieldSelectorControllerTest { + + @isTest + public static void testOFSController() { + ObjectFieldSelectorController.GetObjectsResult result1 = ObjectFieldSelectorController.getObjects('all', new List()); + ObjectFieldSelectorController.GetObjectsResult result2 = ObjectFieldSelectorController.getObjects('both', new List()); + ObjectFieldSelectorController.GetObjectsResult result3 = ObjectFieldSelectorController.getObjects('specific', new List{'Account', 'Opportunity'}); + System.assertEquals(result3.objects.size(), 2); + System.assert(result3.objects.size() < result2.objects.size()); + System.assert(result2.objects.size() < result1.objects.size()); + + ObjectFieldSelectorController.GetObjectFieldsResult result4 = ObjectFieldSelectorController.getObjectFields('Account'); + ObjectFieldSelectorController.GetObjectFieldsResult result5 = ObjectFieldSelectorController.getObjectFields('NotARealObject'); + System.assert(String.isBlank(result4.errorMessage)); + System.assert(!String.isBlank(result5.errorMessage)); + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml new file mode 100644 index 0000000..40d6793 --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.css b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.css new file mode 100644 index 0000000..70ed2a5 --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.css @@ -0,0 +1,3 @@ +.disabledCursor, .disabledCursor ~ .slds-button { + cursor: not-allowed; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.html b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.html new file mode 100644 index 0000000..385c1db --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.html @@ -0,0 +1,182 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js new file mode 100644 index 0000000..dd13296 --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js @@ -0,0 +1,586 @@ +// Style from: https://www.lightningdesignsystem.com/components/combobox +import { LightningElement, api, track } from 'lwc'; +import { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } from 'c/fsc_comboboxUtils'; + +const VARIANTS = { + BASE: 'base', + STANDARD: 'standard', + LABEL_HIDDEN: 'label-hidden' +} + +const LOAD_COUNT = 50; + +export default class OptionSelector extends LightningElement { + /* PUBLIC PROPERTIES */ + @api publicStyle; + @api publicClass; + @api label; + @api name; + @api customSearchHandler; // Custom function to be executed by handleSearchChange, passed in from a parent component. + @api messageWhenValueMissing = 'Please select at least one option.'; + @api iconSize = 'x-small'; + @api placeholder = 'Select an option'; + @api noMatchString = 'No matches found'; + @api valueDelimiter = ','; + @api rightIcon = 'utility:down'; // Icon to be displayed on the right side of the search input + @api groupingTextClass = 'slds-listbox__option-header'; + @api fieldLevelHelp; + @api errorMessage; + @api variant; + @api required = false; + @api disabled = false; + @api isLoading = false; + @api allowMultiselect = false; + // @api variant = VARIANTS.STANDARD; // RESERVED FOR FUTURE USE If set to 'base', when allowMultiselect is false, when the combobox has a value set it will appear like a base combobox rather than as an autocomplete + @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). + @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. + @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + @api filterActions = false; // If true, action items will be filtered along with selection items. By default, action items are always visible + @api showSelectedCount = false; // If true, when allowMultiselect is true, the component label will show the number of selected values in parentheses + @api hideSelectedValues = false; // Reserved for future use + + @api builderContext; + + /* PRIVATE PROPERTIES */ + @track _options = []; + @track _values = []; + @track _groupings = []; + @track onRender = {}; // Used to manage actions on render + @track onLoad = []; + pillsNotFittingCount = 0; + numOptionsDisplayed = LOAD_COUNT; + pillContainerIsExpanded = false; + pillsGoMultiLine = false; + pillTops = []; + debounceTimer; + showList; + _highlightedOptionIndex; + + /* PUBLIC GETTERS & SETTERS */ + @api + get debounceDelay() { + return this._debounceDelay; + } + set debounceDelay(delay) { + this._debounceDelay = parseInt(delay) || 0; + } + _debounceDelay = 0; + + @api + get options() { + return this._options || []; + } + set options(options) { + let groupings = []; + if (Array.isArray(options)) { + this._options = options.map((option, index) => { + if (option.grouping && !groupings.includes(option.grouping)) { + groupings.push(option.grouping); + } + return this.getComboboxOption(option, index); + }); + + if (groupings.length) { + let newIndex = 0; + let groupedOptions = []; + this._options.filter(option => !option.grouping).forEach(groupingOption => { + groupingOption.index = newIndex; + groupedOptions.push(groupingOption); + newIndex++; + }); + + groupings.forEach(grouping => { + groupedOptions.push({ label: grouping, isGrouping: true, index: newIndex }); + newIndex++; + this._options.filter(option => option.grouping == grouping).forEach(groupingOption => { + groupingOption.index = newIndex; + groupedOptions.push(groupingOption); + newIndex++; + }); + }) + this._options = groupedOptions; + } + this.filterOptions(); + } else { + this._options = []; + } + } + + @api + get values() { + return this._values || []; + } + set values(values) { + this._values = setValuesFromMultipleInput(values); + // if (!values) { + // this._values = []; + // } else { + // this._values = Array.isArray(values) ? [...values] : [values]; + // } + } + + @api + get value() { + return this.values.join(this.valueDelimiter); + } + set value(value) { + this.values = setValuesFromSingularInput(value, this.valueDelimiter, this.allowMultiselect); + // if (!value) { + // this.values = []; + // } else { + // this.values = this.allowMultiselect ? value.split(this.valueDelimiter).map(val => val.trim()) : [value]; + // } + } + + @api + get groupings() { + return this._groupings || []; + } + set groupings(value) { + this._groupings = value.map(grouping => { + return { + value: grouping.value, + label: grouping.label + } + }) + let groupedOptions = []; + value.forEach(grouping => { + let currentGroupingOptions = grouping.options.map(option => { + return { + ...option, + grouping: grouping.label + } + }); + groupedOptions.push(...currentGroupingOptions); + }); + this.options = groupedOptions; + } + + @api + get selectedOptions() { + let selectedOptions = []; + this.values.forEach(value => { + const option = this.options.find(option => option.value === value); + if (option) { + selectedOptions.push(option); + } + }); + return selectedOptions; + } + + get selectedOption() { + return this.selectedOptions.length ? this.selectedOptions[0] : null; + } + + /* PUBLIC FUNCTIONS */ + @api + reportValidity() { + if (!this.required || this.selectedOptions.length) { + this.setCustomValidity(); + } else { + this.setCustomValidity(this.messageWhenValueMissing); + } + return !this.errorMessage; + } + + @api + validate() { + if (this.reportValidity()) { + return { isValid: true }; + } else { + return { + isValid: false, + errorMessage: this.errorMessage + } + } + } + + @api + setCustomValidity(errorMessage) { + this.errorMessage = errorMessage; + } + + /* LIFECYCLE HOOKS */ + connectedCallback() { + window.addEventListener("resize", () => { this.resizePillContainer() }); + + } + + renderedCallback() { + if (this.onRender.inputFocus) { + this.onRender.inputFocus = false; + this.inputElement?.focus(); + // this.inputElement ? this.inputElement.focus() : this.template.querySelector('.slds-combobox__input').focus(); + } + if (this.onRender.highlightOption) { + this.onRender.highlightOption = false; + const highlightedOption = this.template.querySelector('[data-has-focus="true"]'); + this.scrollIntoViewIfNeeded(highlightedOption, this.listboxElement); + } + + // Check to see if the arrangement of pills has changed since last render + let newPillTops = [...this.pillElements].map(pill => pill.offsetTop); + if (!(this.pillTops.length == newPillTops.length && this.pillTops.every((val, index) => val === newPillTops[index]))) { + this.pillTops = newPillTops; + this.resizePillContainer(); + } + } + + /* PRIVATE GETTERS AND SETTERS */ + get highlightedOptionIndex() { + return this._highlightedOptionIndex; + } + set highlightedOptionIndex(value) { + this._highlightedOptionIndex = value; + this.options.forEach(option => option.hasFocus = option.index === this.highlightedOptionIndex); // Update the hasFocus property for all options + } + + /* DOM ELEMENT GETTERS */ + get inputElement() { + return this.template.querySelector('input'); + } + + get listboxElement() { + return this.template.querySelector('[role="listbox"]'); + } + + get pillElements() { + return this.template.querySelectorAll('lightning-pill'); + } + + /* COMPUTED LOGIC VALUES */ + get displayedOptions() { + return this.options.slice(0, this.numOptionsDisplayed); + } + + get isInputDisabled() { + return this.disabled || this.isLoading; + } + + get noMatchFound() { + return this.options.every(option => option.hidden || option.isAction); + } + + get showSelectedValue() { + return !this.allowMultiselect && this.selectedOption; + } + + get showPills() { + return this.allowMultiselect && !this.hidePills && this.values.length; + } + + get computedLabel() { + return this.label + ((this.allowMultiselect && this.showSelectedCount) ? ' (' + this.values.length + ')' : ''); + } + + get isBaseVariant() { + return this.variant === VARIANTS.BASE; + } + + get showLabel() { + return this.variant !== VARIANTS.LABEL_HIDDEN; + } + + /* COMPUTED CSS CLASS STRINGS */ + get computedSelectedValueClass() { + return 'slds-combobox__form-element slds-input-has-icon' + (this.selectedOption?.icon ? ' slds-input-has-icon_left-right' : ' slds-input-has-icon_right'); + } + + get computedFormElementClass() { + return 'slds-form-element' + (this.errorMessage ? ' slds-has-error' : ''); + } + + get computedComboboxContainerClass() { + return 'slds-combobox_container' + ((this.value && !this.isBaseVariant) ? ' slds-has-selection' : ''); + } + + get computedComboboxClass() { + return 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click' + (this.showList ? ' slds-is-open' : ''); + } + + get computedListboxSelectionGroupClass() { + return 'slds-listbox_selection-group' + (this.pillContainerIsExpanded ? ' slds-is-expanded' : ''); + } + + get computedFauxInputClass() { + return 'slds-input_faux slds-combobox__input slds-combobox__input-value' + (this.disabled ? ' slds-theme_shade disabledCursor' : ''); + } + + /* ACTION FUNCTIONS */ + openList() { + this.showList = true; + this.onRender.inputFocus = true; + } + + closeList() { + this.showList = false; + this.highlightedOptionIndex = undefined; + this.numOptionsDisplayed = LOAD_COUNT; + if (this.listboxElement) + this.listboxElement.scrollTop = 0; + } + + resetSearch() { + this.inputElement.value = ''; + this.filterOptions(); + } + + filterOptions() { + let searchText = (this.inputElement?.value || '').toLowerCase(); + // console.log('in filterOptions', searchText); + let numDisplayedCount = 0; + for (let option of this.options) { + if (numDisplayedCount > this.numOptionsDisplayed) { + option.hidden = true; + } else if (searchText && option.isGrouping) { + option.hidden = true; + } else if (this.values.includes(option.value)) { + // If the option has already been selected, hide it from the list of available options + option.hidden = true; + } + else { + // If the option's label matches the search text, display it. Also optionally check the option's sublabel and value. + if (option.label.toLowerCase().includes(searchText) + || (this.includeValueInFilter && option.value.toLowerCase().includes(searchText)) + || (!this.excludeSublabelInFilter && option.sublabel && option.sublabel.toLowerCase().includes(searchText))) { + option.hidden = false; + if (option.grouping) { + this.options.find(grouping => grouping.isGrouping && grouping.label == option.grouping).hidden = false; + } + } else { + option.hidden = true; + } + } + + if (!option.hidden) { + numDisplayedCount++; + } + } + } + + selectOption(index) { + let selectedOption = this.options[index]; + // console.log('selecting '+ JSON.stringify(selectedOption)); + // console.log('value before adding: '+ this.value); + // console.log('values before adding: '+ JSON.stringify(this.values) +', length: '+ this.values.length); + if (!selectedOption) { + return; + } + if (selectedOption.isAction) { + this.dispatchEvent(new CustomEvent('customaction', { detail: selectedOption.value })); + } else { + this.values.push(selectedOption.value); + this.values = this.values; + // this.values = [...this.values, selectedOption.value]; // using spread instead of values.push to trigger the setter + this.resetSearch(); + this.dispatchOptions(); + this.onRender.inputFocus = true; + } + } + + unselectOption(index) { + this.values = [...this.values.slice(0, index), ...this.values.slice(Number(index) + 1)]; + this.dispatchOptions(); + } + + dispatchOptions() { + let detail = { + value: this.value, + values: this.values, + //selectedOptions: this.selectedOptions + } + this.dispatchEvent(new CustomEvent('change', { detail })); + } + + highlightNextOption(startIndex) { + if (!startIndex || startIndex >= this.options.length) { + startIndex = 0; + } + if (this.options[startIndex].hidden || this.options[startIndex].isGrouping) { + this.highlightNextOption(Number(startIndex) + 1); + } else { + this.highlightOption(startIndex); + } + } + + highlightPreviousOption(startIndex) { + if ((startIndex !== 0 && !startIndex) || startIndex < 0) { + startIndex = this.options.length - 1; + } + if (this.options[startIndex].hidden || this.options[startIndex].isGrouping) { + this.highlightPreviousOption(Number(startIndex) - 1); + } else { + this.highlightOption(startIndex); + } + } + + highlightOption(index) { + this.highlightedOptionIndex = index; + this.onRender.highlightOption = true; + } + + resizePillContainer() { + let notFittingCount = 0; + this.pillElements.forEach((pill) => { + if (pill.offsetTop > this.pillElements[0].offsetTop + this.pillElements[0].getBoundingClientRect().height) { + notFittingCount += 1; + } + }); + this.pillsNotFittingCount = notFittingCount; + } + + /* EVENT HANDLERS */ + handleSearchChange(event) { + let searchText = event.target.value; + this.openList(); + this.debounce( + () => this.customSearchHandler ? this.customSearchHandler(searchText) : this.filterOptions(), + this.debounceDelay + ); + } + + handleSearchClick() { + this.handleSearchFocus(); + this.openList(); + } + + handleSearchFocus() { + this.filterOptions(); + this.errorMessage = ''; + } + + handleSearchBlur() { + if (this.inputElement.value && !this.showSelectedValue) { + let matchingValue = this.options.find(option => option.value?.toLowerCase() == this.inputElement.value?.toLowerCase()); + // let matchingValue = this.options.find(option => { + // console.log('searching option: '+ JSON.stringify(option) +', comparing it to '+ this.inputElement.value); + // return option.value?.toLowerCase() == this.inputElement.value?.toLowerCase() + // }); + if (matchingValue) { + this.selectOption(matchingValue.index); + } + } + this.closeList(); + this.reportValidity(); + } + + handleSearchKeydown(event) { + if (this.disabled) { + return; + } + if (event.key === KEYS.DOWN || event.key === KEYS.UP || event.key === KEYS.ENTER) { + if (!this.showList) { + this.openList(); + event.key === KEYS.UP ? this.highlightPreviousOption(this.highlightedOptionIndex) : this.highlightNextOption(this.highlightedOptionIndex); + } else { + if (this.options.some(option => !option.hidden)) { + if (event.key === KEYS.ENTER) { + this.selectOption(this.highlightedOptionIndex); + this.resetSearch(); + this.closeList(); + } else { + event.preventDefault(); + event.stopPropagation(); + event.key === KEYS.UP ? this.highlightPreviousOption(Number(this.highlightedOptionIndex) - 1) : this.highlightNextOption(Number(this.highlightedOptionIndex) + 1); + } + } + } + } + + if (event.key === KEYS.ESCAPE) { + event.preventDefault(); + event.stopPropagation(); + if (this.showSelectedValue) { + this.handleClearClick(); + } else { + this.resetSearch(); + this.closeList(); + } + } + } + + handleOptionSelect(event) { + this.selectOption(event.currentTarget.dataset.index); + } + + handleOptionUnselect(event) { + this.unselectOption(event.target.dataset.index); + } + + handleOptionMouseenter(event) { + this.highlightedOptionIndex = event.currentTarget.dataset.index; + } + + handleOptionMouseleave() { + this.highlightedOptionIndex = undefined; + } + + handleClearClick() { + if (!this.disabled) { + this.values = []; + this.dispatchOptions(); + this.openList(); + } + } + + handleSelectedValueClick() { + if (this.isBaseVariant) { + this.openList(); + this.highlightOption(this.selectedOption.index); + } + } + + handleCollapsePillContainer() { + this.pillContainerIsExpanded = false; + this.resizePillContainer(); + } + + handleExpandPillContainer() { + this.pillContainerIsExpanded = true; + this.resizePillContainer(); + } + + handleListboxScroll(event) { + if (!event.target) + return; + const lastDisplayedOption = this.template.querySelector('.slds-listbox__item:last-child'); + const ul = this.template.querySelector('.slds-listbox'); + let ot = lastDisplayedOption?.offsetTop + if (event.target.scrollTop + event.target.offsetHeight > ot) { + this.numOptionsDisplayed += LOAD_COUNT; + this.filterOptions(); + } + + } + + /* UTILITY FUNCTIONS */ + debounce(fn, wait) { + clearTimeout(this.debounceTimer); + this.debounceTimer = setTimeout(fn, wait); + } + + getComboboxOption(option, index) { + return { + ...option, + index, + get comboboxClass() { + return 'slds-media slds-media_center slds-listbox__option slds-listbox__option_has-meta slds-listbox__option_plain' + (this.hasFocus ? ' slds-has-focus' : ''); + } + } + } + + // Lovingly "borrowed" from https://github.com/salesforce/base-components-recipes/blob/83b87d3772557a22de16f74a047a087a51c4934c/force-app/main/default/lwc/baseCombobox/baseCombobox.js#L836 + scrollIntoViewIfNeeded(element, scrollingParent) { + const parentRect = scrollingParent.getBoundingClientRect(); + const findMeRect = element.getBoundingClientRect(); + if (findMeRect.top <= parentRect.top) { + if (element.offsetTop + findMeRect.height < parentRect.height) { + scrollingParent.scrollTop = 0; + } else { + scrollingParent.scrollTop = element.offsetTop; + } + } else if (findMeRect.bottom >= parentRect.bottom) { + scrollingParent.scrollTop += findMeRect.bottom - parentRect.bottom; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml new file mode 100644 index 0000000..bde6546 --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml @@ -0,0 +1,14 @@ + + + 52.0 + true + Combobox + + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js new file mode 100644 index 0000000..7af1721 --- /dev/null +++ b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js @@ -0,0 +1,33 @@ +const KEYS = { + ESCAPE: 'Escape', + UP: 'ArrowUp', + DOWN: 'ArrowDown', + ENTER: 'Enter' +} + +const setValuesFromMultipleInput = (values) => { + if (!values) { + return []; + } else { + return Array.isArray(values) ? [...values] : [values]; + } +} + +const setValuesFromSingularInput = (value, delimiter, isMultiSelect) => { + if (!value) { + return []; + } else { + return isMultiSelect ? value.split(delimiter).map(val => val.trim()) : [value]; + } +} + +const includesIgnoreCase = (valueToSearch, valueToSearchFor) => { + if (Array.isArray(valueToSearch)) { + return valueToSearch.map(arrayValue => arrayValue.toLowerCase()).includes(valueToSearchFor.toLowerCase()); + } else { + return valueToSearch.toLowerCase().includes(valueToSearchFor.toLowerCase()); + } + +} + +export { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml new file mode 100644 index 0000000..3f28286 --- /dev/null +++ b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html new file mode 100644 index 0000000..32589e5 --- /dev/null +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js new file mode 100644 index 0000000..df67709 --- /dev/null +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js @@ -0,0 +1,235 @@ +import { LightningElement, api, track, wire } from 'lwc'; +import { getObjectInfo } from 'lightning/uiObjectInfoApi'; +import getObjectFields from '@salesforce/apex/ObjectFieldSelectorController.getObjectFields'; +import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } from 'c/fsc_comboboxUtils'; + +const DATA_TYPE_ICONS = { + Address: 'utility:location', + Boolean: 'utility:check', + ComboBox: 'utility:picklist_type', + Currency: 'utility:currency', + Date: 'utility:date_input', + DateTime: 'utility:date_time', + Double: 'utility:number_input', + Email: 'utility:email', + Int: 'utility:number_input', + Location: 'utility:location', + MultiPicklist: 'utility:multi_picklist', + Percent: 'utility:percent', + Phone: 'utility:phone_portrait', + Picklist: 'utility:picklist_type', + Reference: 'utility:record_lookup', + Time: 'utility:clock', + Url: 'utility:link' +} +const DEFAULT_ICON = 'utility:text'; + +const INVALID_TYPE_ERROR = 'INVALID_TYPE'; + +export default class Fsc_fieldSelector2 extends LightningElement { + @api name; + @api allowMultiselect = false; + @api required = false; + @api label = 'Select Field'; + @api showSelectedCount; + @api publicClass; + @api publicStyle; + @api placeholder = 'Type to search fields'; + @api fieldLevelHelp; + @api valueDelimiter = ','; + @api fieldTypeDelimiter = ';'; // Sometimes an array of availableFieldTypes will contain more than one field type value in a single element, so this allows a separate delimiter to be used to split within the element + @api hideIcons = false; + @api isLoading = false; + @api disabled = false; + @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). + @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. + @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + @api allowReferenceLookups = false; + @track fields = []; + @track _values = []; + @track _availableFieldTypes = []; + @track _availableReferenceTypes = []; + + @api builderContext; + + fieldTypes = transformConstantObject(FIELD_TYPES); + _objectName; + isNotFirstObjectLoad; + errorMessage; + + @api + get objectName() { + return this._objectName; + } + set objectName(value) { + this._objectName = value; + if (!this.objectName) { + this.clearValues(); + } + } + + @api + get values() { + return this._values || []; + } + set values(values) { + this._values = setValuesFromMultipleInput(values); + } + @track _values = []; + + @api + get value() { + return this.values.join(this.valueDelimiter); + } + set value(value) { + this.values = setValuesFromSingularInput(value, this.valueDelimiter, this.allowMultiselect); + } + + @api + get availableFieldTypes() { + return this._availableFieldTypes; + } + set availableFieldTypes(value) { + if (!value) { + this._availableFieldTypes = []; + } else if (Array.isArray(value)) { + this._availableFieldTypes = value; + } else { + let types = []; + value.split(this.valueDelimiter).forEach(value => { + types.push(...value.split(this.fieldTypeDelimiter).map(fieldType => fieldType.toLowerCase())); + }) + this._availableFieldTypes = types; + } + } + + @api + get availableReferenceTypes() { + return this._availableReferenceTypes; + } + set availableReferenceTypes(value) { + if (!value) { + this.values = []; + } else { + this._availableReferenceTypes = value.split(this.valueDelimiter).map(val => val.trim()); + } + } + + @api + reportValidity() { + return this.template.querySelector('c-fsc_combobox').reportValidity(); + } + + @api + validate() { + // console.log('in fieldSelector validate, returning '+ JSON.stringify(this.template.querySelector('c-fsc_combobox').validate())); + return this.template.querySelector('c-fsc_combobox').validate(); + } + + get isLoadingOrDisabled() { + return this.isLoading || this.disabled || !this.objectName; + } + + get computedPlaceholder() { + if (!this.objectName) { + return 'No object selected, please select an object'; + } else if (this.isLoading) { + return 'Loading...'; + } else { + return this.placeholder; + } + } + + @wire(getObjectInfo, { objectApiName: '$objectName' }) + handleGetObjectInfo({ error, data }) { + if (error) { + console.log('Fieldselector error: ' + JSON.stringify(error)); + if (error.body.errorCode === INVALID_TYPE_ERROR) { + this.loadObjectInfo(); + } else { + this.errorMessage = 'Unknown error'; + if (Array.isArray(error.body)) { + this.errorMessage = error.body.map(e => e.message).join(', '); + } else if (typeof error.body.message === 'string') { + this.errorMessage = error.body.message; + } + } + } else if (data) { + console.log(JSON.stringify(Object.values(data.fields).filter(field => field.relationshipName)[0])); + this.processFields(Object.values(data.fields)); + } else { + console.log('neither data nor error'); + } + this.isLoading = false; + } + + loadObjectInfo() { + if (!this.objectName || this.isNotFirstObjectLoad) { + this.clearValues(); + } + if (this.objectName) { + this.isLoading = true; + this.disabled = false; + this.isNotFirstObjectLoad = true; + getObjectFields({ objectName: this.objectName }) + .then(result => { + this.processFields(result.fields); + }).catch(error => { + console.log('getObjectFields error: ' + JSON.stringify(error)); + this.errorMessage = error.errorMessage || 'Unknown error'; + }).finally(() => { + this.isLoading = false; + console.log('finished loadObjectInfo'); + }) + } + } + + /* EVENT HANDLERS */ + handleComboboxChange(event) { + this.values = event.detail.values; + this.dispatchFields(); + } + + /* ACTION FUNCTIONS */ + processFields(fields) { + if (this.availableFieldTypes?.length) { + fields = fields.filter(field => includesIgnoreCase(this.availableFieldTypes, field.dataType)); + if (this.availableReferenceTypes?.length) { + fields = fields.filter(field => !field.referenceToInfos.length || field.referenceToInfos.some(ref => includesIgnoreCase(this.availableReferenceTypes, ref.apiName))); + } + } + this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, this.hideIcons ? null : this.getIconFromDataType(field.dataType))); + this.fields.sort((a, b) => { + return a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1; + }); + + } + + clearValues() { + console.log('in clearValues'); + if (this.values.length) { + console.log('actually clearing because there are values to clear (' + this.values + ')'); + this.values = []; + this.dispatchFields(); + } + } + + dispatchFields() { + let detail = { + value: this.value, + values: this.values, + } + this.dispatchEvent(new CustomEvent('change', { detail })); + } + + /* UTILITY FUNCTIONS */ + getIconFromDataType(type) { + let matchingType = this.fieldTypes.options.find(fieldType => includesIgnoreCase(fieldType.value.split(this.fieldTypeDelimiter), type)); + return matchingType?.icon || DEFAULT_ICON; + } + + newField(label, sublabel, value, icon) { + return { label, sublabel, value, icon } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml new file mode 100644 index 0000000..884004a --- /dev/null +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js new file mode 100644 index 0000000..8e5e25a --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js @@ -0,0 +1,58 @@ +const FIELD_TYPES = { + REFERENCE: { label: 'Lookup/Master-Detail', value: 'Reference', icon: 'utility:record_lookup' }, + ADDRESS: { label: 'Address', value: 'Address', icon: 'utility:location' }, + CHECKBOX: { label: 'Checkbox', value: 'Boolean', icon: 'utility:check' }, + CURRENCY: { label: 'Currency', value: 'Currency', icon: 'utility:currency' }, + DATE: { label: 'Date', value: 'Date', icon: 'utility:date_input' }, + DATETIME: { label: 'Date/Time', value: 'DateTime', icon: 'utility:date_time' }, + EMAIL: { label: 'Email', value: 'Email', icon: 'utility:email' }, + LOCATION: { label: 'Geolocation', value: 'Location', icon: 'utility:location' }, + NUMBER: { label: 'Number', value: 'Integer;Double;Int;Long', icon: 'utility:number_input' }, + PERCENT: { label: 'Percent', value: 'Percent', icon: 'utility:percent' }, + PHONE: { label: 'Phone Number', value: 'Phone', icon: 'utility:phone_portrait' }, + PICKLIST: { label: 'Picklist', value: 'Picklist;ComboBox', icon: 'utility:picklist_type' }, + MULTIPICKLIST: { label: 'Picklist (Multi-Select)', value: 'MultiPicklist', icon: 'utility:multi_picklist' }, + TEXT: { label: 'Text', value: 'String', icon: 'utility:text' }, + TEXTAREA: { label: 'Text Area', value: 'TextArea', icon: 'utility:textbox' }, + TEXTENCRYPTED: { label: 'Text (Encrypted)', value: 'EncryptedString', icon: 'utility:hide' }, + TIME: { label: 'Time', value: 'Time', icon: 'utility:clock' }, + URL: { label: 'URL', value: 'URL', icon: 'utility:link' }, +}; + +const DISPLAY_TYPE_OPTIONS = { + OBJECT: { label: 'Just Object(s)', value: 'object' }, + FIELD: { label: 'Just Field(s)', value: 'field' }, + BOTH: { label: 'Both', value: 'both', default: true } +} + +const AVAILABLE_OBJECT_OPTIONS = { + BOTH: { label: 'Custom and Standard Objects', value: 'both', subcategories: ['standard', 'custom'], default: true }, + STANDARD: { label: 'Standard Objects Only', value: 'standard' }, + CUSTOM: { label: 'Custom Objects Only', value: 'custom' }, + ALL: { label: 'ALL Objects (advanced)', value: 'all', subcategories: ['standard', 'custom', 'ancillary'] }, + ANCILLARY: { label: 'Ancillary Objects Only', value: 'ancillary', hide: true }, + SPECIFIC: { label: 'Select Specific Objects', value: 'specific' } +} + +const LAYOUT_OPTIONS = { + VERTICAL: { label: 'Vertical', value: 'vertical', default: true}, + HORIZONTAL: { label: 'Horizontal', value: 'horizontal' }, +} + +const transformConstantObject = (constant) => { + return { + list: constant, + get options() { return Object.values(this.list).filter(option => !option.hide); }, + get default() { return this.options.find(option => option.default); }, + findFromValue: function (value) { + let entry = this.options.find(option => option.value == value); + return entry || this.default; + }, + findFromLabel: function (label) { + let entry = this.options.find(option => option.label == label); + return entry || this.default; + } + } +} + +export { FIELD_TYPES, DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, LAYOUT_OPTIONS, transformConstantObject } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml new file mode 100644 index 0000000..3f28286 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html new file mode 100644 index 0000000..6d62dd2 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js new file mode 100644 index 0000000..172bf36 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js @@ -0,0 +1,157 @@ +import { LightningElement, wire, track, api } from 'lwc'; +import getObjects from '@salesforce/apex/ObjectFieldSelectorController.getObjects'; +import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_comboboxUtils'; + +const ANCILLARY_SUFFIXES = ['Feed', 'Tag', 'Share', 'ChangeEvent', 'History']; +export default class Fsc_objectSelector extends LightningElement { + availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); + + @api name; + @api allowMultiselect = false; + @api required = false; + @api label = 'Select Object'; + @api placeholder = 'Type to search objects'; + @api showSelectedCount; + @api publicClass; + @api publicStyle; + @api fieldLevelHelp; + @api variant; + @api hideIcons = false; + @api valueDelimiter = ','; + @api isLoading = false; + @api disabled = false; + @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). + @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. + @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + // @api availableObjectSelection = this.availableObjectOptions.default?.value; + @api availableObjects = []; + + @api builderContext; + + hasConnected = false; + @track allOptions = []; + @track loadedCategories = []; + + @api + get values() { + return this._values || []; + } + set values(values) { + this._values = setValuesFromMultipleInput(values); + } + @track _values = []; + + @api + get value() { + return this.values.join(this.valueDelimiter); + } + set value(value) { + this.values = setValuesFromSingularInput(value, this.valueDelimiter, this.allowMultiselect); + } + + @api + get availableObjectSelection() { + return this._availableObjectSelection; + } + set availableObjectSelection(value) { + console.log(' in set availableObjectSelection to ' + value); + this._availableObjectSelection = value; + if (this.hasConnected && this.values.length) { + this.values = []; + this.dispatchObjects(); + } + // if (!this.loadedCategories.includes(this.availableObjectSelection)) { + // this.loadObjectCategory(this.availableObjectSelection); + // } + } + _availableObjectSelection = this.availableObjectOptions.default?.value; + + get objectOptions() { + return this.allOptions.filter(option => { + if (this.availableObjectSelection === AVAILABLE_OBJECT_OPTIONS.SPECIFIC.value) { + return this.availableObjects?.includes(option.value); + } else { + return this.matchesObjectCategory(option.category); + } + }); + } + + get computedPlaceholder() { + return this.isLoading ? 'Loading...' : this.placeholder; + } + + // @api + // get availableObjects() { + // return this._availableObjects; + // } + // set availableObjects(value) { + // this._availableObjects = value; + // if(this.hasConnected) + // this.loadObjects(); + // } + // _availableObjects = [] + + addObjectOptions(options, category) { + let newOptions = options.map(objectType => { + return { + category, + label: objectType.label, + sublabel: objectType.value, + value: objectType.value, + } + }); + this.allOptions = [...this.allOptions, ...newOptions].sort((a, b) => { + return a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1; + }); + } + + loadObjectCategory(category) { + if (!this.value) { + this.isLoading = true; + } + getObjects({ selectionType: category }) + .then(result => { + this.addObjectOptions(result.objects, category); + this.isLoading = false; + }); + } + + @api + reportValidity() { + return this.template.querySelector('c-fsc_combobox').reportValidity(); + } + + @api + validate() { + return this.template.querySelector('c-fsc_combobox').validate(); + } + + connectedCallback() { + this.hasConnected = true; + let initialLoadCategories = [AVAILABLE_OBJECT_OPTIONS.STANDARD.value, AVAILABLE_OBJECT_OPTIONS.CUSTOM.value, AVAILABLE_OBJECT_OPTIONS.ANCILLARY.value]; + initialLoadCategories.forEach(category => { + this.loadObjectCategory(category); + }); + } + + handleComboboxChange(event) { + this.values = event.detail.values; + this.dispatchObjects(); + } + + dispatchObjects() { + let detail = { + value: this.value, + values: this.values, + } + console.log('dispatching objects', JSON.stringify(detail)); + this.dispatchEvent(new CustomEvent('change', { detail })); + } + + matchesObjectCategory(category) { + return category === this.availableObjectSelection || + this.availableObjectSelection === AVAILABLE_OBJECT_OPTIONS.ALL.value || + (this.availableObjectSelection === AVAILABLE_OBJECT_OPTIONS.BOTH.value && (category === AVAILABLE_OBJECT_OPTIONS.STANDARD.value || category === AVAILABLE_OBJECT_OPTIONS.CUSTOM.value)) + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml new file mode 100644 index 0000000..ba22d67 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml @@ -0,0 +1,15 @@ + + + 54.0 + true + + lightning__FlowScreen + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/iconSelector/iconSelector.html b/force-app/main/default/lwc/iconSelector/iconSelector.html new file mode 100644 index 0000000..b8a5e2f --- /dev/null +++ b/force-app/main/default/lwc/iconSelector/iconSelector.html @@ -0,0 +1,45 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/iconSelector/iconSelector.js b/force-app/main/default/lwc/iconSelector/iconSelector.js new file mode 100644 index 0000000..3f199ab --- /dev/null +++ b/force-app/main/default/lwc/iconSelector/iconSelector.js @@ -0,0 +1,1406 @@ +import { LightningElement, track, api } from 'lwc'; + +const TABLE_STYLE = "height: 400px; width:99%"; + +// Icons updated 6/3/21 +// Lightning Design System Release 2.15.8 - May 27, 2021 + +const ACTION_ICONS = [ + { 'iconName': 'action:add_contact', 'id': 'action:add_contact' }, + { 'iconName': 'action:add_file', 'id': 'action:add_file' }, + { 'iconName': 'action:add_photo_video', 'id': 'action:add_photo_video' }, + { 'iconName': 'action:add_relationship', 'id': 'action:add_relationship' }, + { 'iconName': 'action:adjust_value', 'id': 'action:adjust_value' }, + { 'iconName': 'action:announcement', 'id': 'action:announcement' }, + { 'iconName': 'action:apex', 'id': 'action:apex' }, + { 'iconName': 'action:approval', 'id': 'action:approval' }, + { 'iconName': 'action:back', 'id': 'action:back' }, + { 'iconName': 'action:bug', 'id': 'action:bug' }, + { 'iconName': 'action:call', 'id': 'action:call' }, + { 'iconName': 'action:canvas', 'id': 'action:canvas' }, + { 'iconName': 'action:change_owner', 'id': 'action:change_owner' }, + { 'iconName': 'action:change_record_type', 'id': 'action:change_record_type' }, + { 'iconName': 'action:check', 'id': 'action:check' }, + { 'iconName': 'action:clone', 'id': 'action:clone' }, + { 'iconName': 'action:close', 'id': 'action:close' }, + { 'iconName': 'action:defer', 'id': 'action:defer' }, + { 'iconName': 'action:delete', 'id': 'action:delete' }, + { 'iconName': 'action:description', 'id': 'action:description' }, + { 'iconName': 'action:dial_in', 'id': 'action:dial_in' }, + { 'iconName': 'action:download', 'id': 'action:download' }, + { 'iconName': 'action:edit_groups', 'id': 'action:edit_groups' }, + { 'iconName': 'action:edit_relationship', 'id': 'action:edit_relationship' }, + { 'iconName': 'action:edit', 'id': 'action:edit' }, + { 'iconName': 'action:email', 'id': 'action:email' }, + { 'iconName': 'action:fallback', 'id': 'action:fallback' }, + { 'iconName': 'action:filter', 'id': 'action:filter' }, + { 'iconName': 'action:flow', 'id': 'action:flow' }, + { 'iconName': 'action:follow', 'id': 'action:follow' }, + { 'iconName': 'action:following', 'id': 'action:following' }, + { 'iconName': 'action:freeze_user', 'id': 'action:freeze_user' }, + { 'iconName': 'action:goal', 'id': 'action:goal' }, + { 'iconName': 'action:google_news', 'id': 'action:google_news' }, + { 'iconName': 'action:info', 'id': 'action:info' }, + { 'iconName': 'action:join_group', 'id': 'action:join_group' }, + { 'iconName': 'action:lead_convert', 'id': 'action:lead_convert' }, + { 'iconName': 'action:leave_group', 'id': 'action:leave_group' }, + { 'iconName': 'action:log_a_call', 'id': 'action:log_a_call' }, + { 'iconName': 'action:log_event', 'id': 'action:log_event' }, + { 'iconName': 'action:manage_perm_sets', 'id': 'action:manage_perm_sets' }, + { 'iconName': 'action:map', 'id': 'action:map' }, + { 'iconName': 'action:more', 'id': 'action:more' }, + { 'iconName': 'action:new_account', 'id': 'action:new_account' }, + { 'iconName': 'action:new_campaign', 'id': 'action:new_campaign' }, + { 'iconName': 'action:new_case', 'id': 'action:new_case' }, + { 'iconName': 'action:new_child_case', 'id': 'action:new_child_case' }, + { 'iconName': 'action:new_contact', 'id': 'action:new_contact' }, + { 'iconName': 'action:new_event', 'id': 'action:new_event' }, + { 'iconName': 'action:new_group', 'id': 'action:new_group' }, + { 'iconName': 'action:new_lead', 'id': 'action:new_lead' }, + { 'iconName': 'action:new_note', 'id': 'action:new_note' }, + { 'iconName': 'action:new_notebook', 'id': 'action:new_notebook' }, + { 'iconName': 'action:new_opportunity', 'id': 'action:new_opportunity' }, + { 'iconName': 'action:new_person_account', 'id': 'action:new_person_account' }, + { 'iconName': 'action:new_task', 'id': 'action:new_task' }, + { 'iconName': 'action:new', 'id': 'action:new' }, + { 'iconName': 'action:password_unlock', 'id': 'action:password_unlock' }, + { 'iconName': 'action:preview', 'id': 'action:preview' }, + { 'iconName': 'action:priority', 'id': 'action:priority' }, + { 'iconName': 'action:question_post_action', 'id': 'action:question_post_action' }, + { 'iconName': 'action:quote', 'id': 'action:quote' }, + { 'iconName': 'action:recall', 'id': 'action:recall' }, + { 'iconName': 'action:record', 'id': 'action:record' }, + { 'iconName': 'action:refresh', 'id': 'action:refresh' }, + { 'iconName': 'action:reject', 'id': 'action:reject' }, + { 'iconName': 'action:remove_relationship', 'id': 'action:remove_relationship' }, + { 'iconName': 'action:remove', 'id': 'action:remove' }, + { 'iconName': 'action:reset_password', 'id': 'action:reset_password' }, + { 'iconName': 'action:script', 'id': 'action:script' }, + { 'iconName': 'action:share_file', 'id': 'action:share_file' }, + { 'iconName': 'action:share_link', 'id': 'action:share_link' }, + { 'iconName': 'action:share_poll', 'id': 'action:share_poll' }, + { 'iconName': 'action:share_post', 'id': 'action:share_post' }, + { 'iconName': 'action:share_thanks', 'id': 'action:share_thanks' }, + { 'iconName': 'action:share', 'id': 'action:share' }, + { 'iconName': 'action:sort', 'id': 'action:sort' }, + { 'iconName': 'action:submit_for_approval', 'id': 'action:submit_for_approval' }, + { 'iconName': 'action:update_status', 'id': 'action:update_status' }, + { 'iconName': 'action:update', 'id': 'action:update' }, + { 'iconName': 'action:upload', 'id': 'action:upload' }, + { 'iconName': 'action:user_activation', 'id': 'action:user_activation' }, + { 'iconName': 'action:user', 'id': 'action:user' }, + { 'iconName': 'action:view_relationship', 'id': 'action:view_relationship' }, + { 'iconName': 'action:web_link', 'id': 'action:web_link' } +]; + +const CUSTOM_ICONS = [{ 'iconName': 'custom:custom1', 'id': 'custom:custom1' }, + { 'iconName': 'custom:custom2', 'id': 'custom:custom2' }, + { 'iconName': 'custom:custom3', 'id': 'custom:custom3' }, + { 'iconName': 'custom:custom4', 'id': 'custom:custom4' }, + { 'iconName': 'custom:custom5', 'id': 'custom:custom5' }, + { 'iconName': 'custom:custom6', 'id': 'custom:custom6' }, + { 'iconName': 'custom:custom7', 'id': 'custom:custom7' }, + { 'iconName': 'custom:custom8', 'id': 'custom:custom8' }, + { 'iconName': 'custom:custom9', 'id': 'custom:custom9' }, + { 'iconName': 'custom:custom10', 'id': 'custom:custom10' }, + { 'iconName': 'custom:custom11', 'id': 'custom:custom11' }, + { 'iconName': 'custom:custom12', 'id': 'custom:custom12' }, + { 'iconName': 'custom:custom13', 'id': 'custom:custom13' }, + { 'iconName': 'custom:custom14', 'id': 'custom:custom14' }, + { 'iconName': 'custom:custom15', 'id': 'custom:custom15' }, + { 'iconName': 'custom:custom16', 'id': 'custom:custom16' }, + { 'iconName': 'custom:custom17', 'id': 'custom:custom17' }, + { 'iconName': 'custom:custom18', 'id': 'custom:custom18' }, + { 'iconName': 'custom:custom19', 'id': 'custom:custom19' }, + { 'iconName': 'custom:custom20', 'id': 'custom:custom20' }, + { 'iconName': 'custom:custom21', 'id': 'custom:custom21' }, + { 'iconName': 'custom:custom22', 'id': 'custom:custom22' }, + { 'iconName': 'custom:custom23', 'id': 'custom:custom23' }, + { 'iconName': 'custom:custom24', 'id': 'custom:custom24' }, + { 'iconName': 'custom:custom25', 'id': 'custom:custom25' }, + { 'iconName': 'custom:custom26', 'id': 'custom:custom26' }, + { 'iconName': 'custom:custom27', 'id': 'custom:custom27' }, + { 'iconName': 'custom:custom28', 'id': 'custom:custom28' }, + { 'iconName': 'custom:custom29', 'id': 'custom:custom29' }, + { 'iconName': 'custom:custom30', 'id': 'custom:custom30' }, + { 'iconName': 'custom:custom31', 'id': 'custom:custom31' }, + { 'iconName': 'custom:custom32', 'id': 'custom:custom32' }, + { 'iconName': 'custom:custom33', 'id': 'custom:custom33' }, + { 'iconName': 'custom:custom34', 'id': 'custom:custom34' }, + { 'iconName': 'custom:custom35', 'id': 'custom:custom35' }, + { 'iconName': 'custom:custom36', 'id': 'custom:custom36' }, + { 'iconName': 'custom:custom37', 'id': 'custom:custom37' }, + { 'iconName': 'custom:custom38', 'id': 'custom:custom38' }, + { 'iconName': 'custom:custom39', 'id': 'custom:custom39' }, + { 'iconName': 'custom:custom40', 'id': 'custom:custom40' }, + { 'iconName': 'custom:custom41', 'id': 'custom:custom41' }, + { 'iconName': 'custom:custom42', 'id': 'custom:custom42' }, + { 'iconName': 'custom:custom43', 'id': 'custom:custom43' }, + { 'iconName': 'custom:custom44', 'id': 'custom:custom44' }, + { 'iconName': 'custom:custom45', 'id': 'custom:custom45' }, + { 'iconName': 'custom:custom46', 'id': 'custom:custom46' }, + { 'iconName': 'custom:custom47', 'id': 'custom:custom47' }, + { 'iconName': 'custom:custom48', 'id': 'custom:custom48' }, + { 'iconName': 'custom:custom49', 'id': 'custom:custom49' }, + { 'iconName': 'custom:custom50', 'id': 'custom:custom50' }, + { 'iconName': 'custom:custom51', 'id': 'custom:custom51' }, + { 'iconName': 'custom:custom52', 'id': 'custom:custom52' }, + { 'iconName': 'custom:custom53', 'id': 'custom:custom53' }, + { 'iconName': 'custom:custom54', 'id': 'custom:custom54' }, + { 'iconName': 'custom:custom55', 'id': 'custom:custom55' }, + { 'iconName': 'custom:custom56', 'id': 'custom:custom56' }, + { 'iconName': 'custom:custom57', 'id': 'custom:custom57' }, + { 'iconName': 'custom:custom58', 'id': 'custom:custom58' }, + { 'iconName': 'custom:custom59', 'id': 'custom:custom59' }, + { 'iconName': 'custom:custom60', 'id': 'custom:custom60' }, + { 'iconName': 'custom:custom61', 'id': 'custom:custom61' }, + { 'iconName': 'custom:custom62', 'id': 'custom:custom62' }, + { 'iconName': 'custom:custom63', 'id': 'custom:custom63' }, + { 'iconName': 'custom:custom64', 'id': 'custom:custom64' }, + { 'iconName': 'custom:custom65', 'id': 'custom:custom65' }, + { 'iconName': 'custom:custom66', 'id': 'custom:custom66' }, + { 'iconName': 'custom:custom67', 'id': 'custom:custom67' }, + { 'iconName': 'custom:custom68', 'id': 'custom:custom68' }, + { 'iconName': 'custom:custom69', 'id': 'custom:custom69' }, + { 'iconName': 'custom:custom70', 'id': 'custom:custom70' }, + { 'iconName': 'custom:custom71', 'id': 'custom:custom71' }, + { 'iconName': 'custom:custom72', 'id': 'custom:custom72' }, + { 'iconName': 'custom:custom73', 'id': 'custom:custom73' }, + { 'iconName': 'custom:custom74', 'id': 'custom:custom74' }, + { 'iconName': 'custom:custom75', 'id': 'custom:custom75' }, + { 'iconName': 'custom:custom76', 'id': 'custom:custom76' }, + { 'iconName': 'custom:custom77', 'id': 'custom:custom77' }, + { 'iconName': 'custom:custom78', 'id': 'custom:custom78' }, + { 'iconName': 'custom:custom79', 'id': 'custom:custom79' }, + { 'iconName': 'custom:custom80', 'id': 'custom:custom80' }, + { 'iconName': 'custom:custom81', 'id': 'custom:custom81' }, + { 'iconName': 'custom:custom82', 'id': 'custom:custom82' }, + { 'iconName': 'custom:custom83', 'id': 'custom:custom83' }, + { 'iconName': 'custom:custom84', 'id': 'custom:custom84' }, + { 'iconName': 'custom:custom85', 'id': 'custom:custom85' }, + { 'iconName': 'custom:custom86', 'id': 'custom:custom86' }, + { 'iconName': 'custom:custom87', 'id': 'custom:custom87' }, + { 'iconName': 'custom:custom88', 'id': 'custom:custom88' }, + { 'iconName': 'custom:custom89', 'id': 'custom:custom89' }, + { 'iconName': 'custom:custom90', 'id': 'custom:custom90' }, + { 'iconName': 'custom:custom91', 'id': 'custom:custom91' }, + { 'iconName': 'custom:custom92', 'id': 'custom:custom92' }, + { 'iconName': 'custom:custom93', 'id': 'custom:custom93' }, + { 'iconName': 'custom:custom94', 'id': 'custom:custom94' }, + { 'iconName': 'custom:custom95', 'id': 'custom:custom95' }, + { 'iconName': 'custom:custom96', 'id': 'custom:custom96' }, + { 'iconName': 'custom:custom97', 'id': 'custom:custom97' }, + { 'iconName': 'custom:custom98', 'id': 'custom:custom98' }, + { 'iconName': 'custom:custom99', 'id': 'custom:custom99' }, + { 'iconName': 'custom:custom100', 'id': 'custom:custom100' }, + { 'iconName': 'custom:custom101', 'id': 'custom:custom101' }, + { 'iconName': 'custom:custom102', 'id': 'custom:custom102' }, + { 'iconName': 'custom:custom103', 'id': 'custom:custom103' }, + { 'iconName': 'custom:custom104', 'id': 'custom:custom104' }, + { 'iconName': 'custom:custom105', 'id': 'custom:custom105' }, + { 'iconName': 'custom:custom106', 'id': 'custom:custom106' }, + { 'iconName': 'custom:custom107', 'id': 'custom:custom107' }, + { 'iconName': 'custom:custom108', 'id': 'custom:custom108' }, + { 'iconName': 'custom:custom109', 'id': 'custom:custom109' }, + { 'iconName': 'custom:custom110', 'id': 'custom:custom110' }, + { 'iconName': 'custom:custom111', 'id': 'custom:custom111' }, + { 'iconName': 'custom:custom112', 'id': 'custom:custom112' }, + { 'iconName': 'custom:custom113', 'id': 'custom:custom113' } +] + +const STANDARD_ICONS = [ +    { 'iconName': 'standard:account', 'id': 'standard:account' }, +    { 'iconName': 'standard:action_list_component', 'id': 'standard:action_list_component' }, +    { 'iconName': 'standard:actions_and_buttons', 'id': 'standard:actions_and_buttons' }, +    { 'iconName': 'standard:activation_target', 'id': 'standard:activation_target' }, +    { 'iconName': 'standard:activations', 'id': 'standard:activations' }, +    { 'iconName': 'standard:address', 'id': 'standard:address' }, +    { 'iconName': 'standard:agent_home', 'id': 'standard:agent_home' }, +    { 'iconName': 'standard:agent_session', 'id': 'standard:agent_session' }, +    { 'iconName': 'standard:aggregation_policy', 'id': 'standard:aggregation_policy' }, +    { 'iconName': 'standard:all', 'id': 'standard:all' }, +    { 'iconName': 'standard:announcement', 'id': 'standard:announcement' }, +    { 'iconName': 'standard:answer_best', 'id': 'standard:answer_best' }, +    { 'iconName': 'standard:answer_private', 'id': 'standard:answer_private' }, +    { 'iconName': 'standard:answer_public', 'id': 'standard:answer_public' }, +    { 'iconName': 'standard:apex', 'id': 'standard:apex' }, +    { 'iconName': 'standard:apex_plugin', 'id': 'standard:apex_plugin' }, +    { 'iconName': 'standard:app', 'id': 'standard:app' }, +    { 'iconName': 'standard:approval', 'id': 'standard:approval' }, +    { 'iconName': 'standard:apps', 'id': 'standard:apps' }, +    { 'iconName': 'standard:apps_admin', 'id': 'standard:apps_admin' }, +    { 'iconName': 'standard:article', 'id': 'standard:article' }, +    { 'iconName': 'standard:asset_action', 'id': 'standard:asset_action' }, +    { 'iconName': 'standard:asset_action_source', 'id': 'standard:asset_action_source' }, +    { 'iconName': 'standard:asset_downtime_period', 'id': 'standard:asset_downtime_period' }, +    { 'iconName': 'standard:asset_object', 'id': 'standard:asset_object' }, +    { 'iconName': 'standard:asset_relationship', 'id': 'standard:asset_relationship' }, +    { 'iconName': 'standard:asset_state_period', 'id': 'standard:asset_state_period' }, +    { 'iconName': 'standard:asset_warranty', 'id': 'standard:asset_warranty' }, +    { 'iconName': 'standard:assigned_resource', 'id': 'standard:assigned_resource' }, +    { 'iconName': 'standard:assignment', 'id': 'standard:assignment' }, +    { 'iconName': 'standard:avatar', 'id': 'standard:avatar' }, +    { 'iconName': 'standard:avatar_loading', 'id': 'standard:avatar_loading' }, +    { 'iconName': 'standard:bot', 'id': 'standard:bot' }, +    { 'iconName': 'standard:bot_training', 'id': 'standard:bot_training' }, +    { 'iconName': 'standard:branch_merge', 'id': 'standard:branch_merge' }, +    { 'iconName': 'standard:brand', 'id': 'standard:brand' }, +    { 'iconName': 'standard:bundle_config', 'id': 'standard:bundle_config' }, +    { 'iconName': 'standard:bundle_policy', 'id': 'standard:bundle_policy' }, +    { 'iconName': 'standard:business_hours', 'id': 'standard:business_hours' }, +    { 'iconName': 'standard:buyer_account', 'id': 'standard:buyer_account' }, +    { 'iconName': 'standard:buyer_group', 'id': 'standard:buyer_group' }, +    { 'iconName': 'standard:calculated_insights', 'id': 'standard:calculated_insights' }, +    { 'iconName': 'standard:calibration', 'id': 'standard:calibration' }, +    { 'iconName': 'standard:call', 'id': 'standard:call' }, +    { 'iconName': 'standard:call_coaching', 'id': 'standard:call_coaching' }, +    { 'iconName': 'standard:call_history', 'id': 'standard:call_history' }, +    { 'iconName': 'standard:campaign', 'id': 'standard:campaign' }, +    { 'iconName': 'standard:campaign_members', 'id': 'standard:campaign_members' }, +    { 'iconName': 'standard:cancel_checkout', 'id': 'standard:cancel_checkout' }, +    { 'iconName': 'standard:canvas', 'id': 'standard:canvas' }, +    { 'iconName': 'standard:capacity_plan', 'id': 'standard:capacity_plan' }, +    { 'iconName': 'standard:care_request_reviewer', 'id': 'standard:care_request_reviewer' }, +    { 'iconName': 'standard:carousel', 'id': 'standard:carousel' }, +    { 'iconName': 'standard:case', 'id': 'standard:case' }, +    { 'iconName': 'standard:case_change_status', 'id': 'standard:case_change_status' }, +    { 'iconName': 'standard:case_comment', 'id': 'standard:case_comment' }, +    { 'iconName': 'standard:case_email', 'id': 'standard:case_email' }, +    { 'iconName': 'standard:case_log_a_call', 'id': 'standard:case_log_a_call' }, +    { 'iconName': 'standard:case_milestone', 'id': 'standard:case_milestone' }, +    { 'iconName': 'standard:case_transcript', 'id': 'standard:case_transcript' }, +    { 'iconName': 'standard:case_wrap_up', 'id': 'standard:case_wrap_up' }, +    { 'iconName': 'standard:catalog', 'id': 'standard:catalog' }, +    { 'iconName': 'standard:category', 'id': 'standard:category' }, +    { 'iconName': 'standard:channel_program_history', 'id': 'standard:channel_program_history' }, +    { 'iconName': 'standard:channel_program_levels', 'id': 'standard:channel_program_levels' }, +    { 'iconName': 'standard:channel_program_members', 'id': 'standard:channel_program_members' }, +    { 'iconName': 'standard:channel_programs', 'id': 'standard:channel_programs' }, +    { 'iconName': 'standard:chart', 'id': 'standard:chart' }, +    { 'iconName': 'standard:checkout', 'id': 'standard:checkout' }, +    { 'iconName': 'standard:choice', 'id': 'standard:choice' }, +    { 'iconName': 'standard:client', 'id': 'standard:client' }, +    { 'iconName': 'standard:cms', 'id': 'standard:cms' }, +    { 'iconName': 'standard:coaching', 'id': 'standard:coaching' }, +    { 'iconName': 'standard:code_playground', 'id': 'standard:code_playground' }, +    { 'iconName': 'standard:collection', 'id': 'standard:collection' }, +    { 'iconName': 'standard:collection_variable', 'id': 'standard:collection_variable' }, +    { 'iconName': 'standard:connected_apps', 'id': 'standard:connected_apps' }, +    { 'iconName': 'standard:constant', 'id': 'standard:constant' }, +    { 'iconName': 'standard:contact', 'id': 'standard:contact' }, +    { 'iconName': 'standard:contact_list', 'id': 'standard:contact_list' }, +    { 'iconName': 'standard:contact_request', 'id': 'standard:contact_request' }, +    { 'iconName': 'standard:contract', 'id': 'standard:contract' }, +    { 'iconName': 'standard:contract_line_item', 'id': 'standard:contract_line_item' }, +    { 'iconName': 'standard:currency', 'id': 'standard:currency' }, +    { 'iconName': 'standard:currency_input', 'id': 'standard:currency_input' }, +    { 'iconName': 'standard:custom', 'id': 'standard:custom' }, +    { 'iconName': 'standard:custom_component_task', 'id': 'standard:custom_component_task' }, +    { 'iconName': 'standard:custom_notification', 'id': 'standard:custom_notification' }, +    { 'iconName': 'standard:customer_360', 'id': 'standard:customer_360' }, +    { 'iconName': 'standard:customer_lifecycle_analytics', 'id': 'standard:customer_lifecycle_analytics' }, +    { 'iconName': 'standard:customer_portal_users', 'id': 'standard:customer_portal_users' }, +    { 'iconName': 'standard:customers', 'id': 'standard:customers' }, +    { 'iconName': 'standard:dashboard', 'id': 'standard:dashboard' }, +    { 'iconName': 'standard:dashboard_ea', 'id': 'standard:dashboard_ea' }, +    { 'iconName': 'standard:data_integration_hub', 'id': 'standard:data_integration_hub' }, +    { 'iconName': 'standard:data_mapping', 'id': 'standard:data_mapping' }, +    { 'iconName': 'standard:data_model', 'id': 'standard:data_model' }, +    { 'iconName': 'standard:data_streams', 'id': 'standard:data_streams' }, +    { 'iconName': 'standard:datadotcom', 'id': 'standard:datadotcom' }, +    { 'iconName': 'standard:dataset', 'id': 'standard:dataset' }, +    { 'iconName': 'standard:date_input', 'id': 'standard:date_input' }, +    { 'iconName': 'standard:date_time', 'id': 'standard:date_time' }, +    { 'iconName': 'standard:decision', 'id': 'standard:decision' }, +    { 'iconName': 'standard:default', 'id': 'standard:default' }, +    { 'iconName': 'standard:delegated_account', 'id': 'standard:delegated_account' }, +    { 'iconName': 'standard:device', 'id': 'standard:device' }, +    { 'iconName': 'standard:display_rich_text', 'id': 'standard:display_rich_text' }, +    { 'iconName': 'standard:display_text', 'id': 'standard:display_text' }, +    { 'iconName': 'standard:document', 'id': 'standard:document' }, +    { 'iconName': 'standard:document_reference', 'id': 'standard:document_reference' }, +    { 'iconName': 'standard:drafts', 'id': 'standard:drafts' }, +    { 'iconName': 'standard:duration_downscale', 'id': 'standard:duration_downscale' }, +    { 'iconName': 'standard:dynamic_record_choice', 'id': 'standard:dynamic_record_choice' }, +    { 'iconName': 'standard:education', 'id': 'standard:education' }, +    { 'iconName': 'standard:einstein_replies', 'id': 'standard:einstein_replies' }, +    { 'iconName': 'standard:email', 'id': 'standard:email' }, +    { 'iconName': 'standard:email_chatter', 'id': 'standard:email_chatter' }, +    { 'iconName': 'standard:employee', 'id': 'standard:employee' }, +    { 'iconName': 'standard:employee_asset', 'id': 'standard:employee_asset' }, +    { 'iconName': 'standard:employee_contact', 'id': 'standard:employee_contact' }, +    { 'iconName': 'standard:employee_job', 'id': 'standard:employee_job' }, +    { 'iconName': 'standard:employee_job_position', 'id': 'standard:employee_job_position' }, +    { 'iconName': 'standard:employee_organization', 'id': 'standard:employee_organization' }, +    { 'iconName': 'standard:empty', 'id': 'standard:empty' }, +    { 'iconName': 'standard:endorsement', 'id': 'standard:endorsement' }, +    { 'iconName': 'standard:entitlement', 'id': 'standard:entitlement' }, +    { 'iconName': 'standard:entitlement_policy', 'id': 'standard:entitlement_policy' }, +    { 'iconName': 'standard:entitlement_process', 'id': 'standard:entitlement_process' }, +    { 'iconName': 'standard:entitlement_template', 'id': 'standard:entitlement_template' }, +    { 'iconName': 'standard:entity', 'id': 'standard:entity' }, +    { 'iconName': 'standard:entity_milestone', 'id': 'standard:entity_milestone' }, +    { 'iconName': 'standard:environment_hub', 'id': 'standard:environment_hub' }, +    { 'iconName': 'standard:event', 'id': 'standard:event' }, +    { 'iconName': 'standard:events', 'id': 'standard:events' }, +    { 'iconName': 'standard:expense', 'id': 'standard:expense' }, +    { 'iconName': 'standard:expense_report', 'id': 'standard:expense_report' }, +    { 'iconName': 'standard:expense_report_entry', 'id': 'standard:expense_report_entry' }, +    { 'iconName': 'standard:feed', 'id': 'standard:feed' }, +    { 'iconName': 'standard:feedback', 'id': 'standard:feedback' }, +    { 'iconName': 'standard:file', 'id': 'standard:file' }, +    { 'iconName': 'standard:filter', 'id': 'standard:filter' }, +    { 'iconName': 'standard:filter_criteria', 'id': 'standard:filter_criteria' }, +    { 'iconName': 'standard:filter_criteria_rule', 'id': 'standard:filter_criteria_rule' }, +    { 'iconName': 'standard:first_non_empty', 'id': 'standard:first_non_empty' }, +    { 'iconName': 'standard:flow', 'id': 'standard:flow' }, +    { 'iconName': 'standard:folder', 'id': 'standard:folder' }, +    { 'iconName': 'standard:forecasts', 'id': 'standard:forecasts' }, +    { 'iconName': 'standard:form', 'id': 'standard:form' }, +    { 'iconName': 'standard:formula', 'id': 'standard:formula' }, +    { 'iconName': 'standard:fulfillment_order', 'id': 'standard:fulfillment_order' }, +    { 'iconName': 'standard:generic_loading', 'id': 'standard:generic_loading' }, +    { 'iconName': 'standard:global_constant', 'id': 'standard:global_constant' }, +    { 'iconName': 'standard:goals', 'id': 'standard:goals' }, +    { 'iconName': 'standard:group_loading', 'id': 'standard:group_loading' }, +    { 'iconName': 'standard:groups', 'id': 'standard:groups' }, +    { 'iconName': 'standard:guidance_center', 'id': 'standard:guidance_center' }, +    { 'iconName': 'standard:hierarchy', 'id': 'standard:hierarchy' }, +    { 'iconName': 'standard:high_velocity_sales', 'id': 'standard:high_velocity_sales' }, +    { 'iconName': 'standard:holiday_operating_hours', 'id': 'standard:holiday_operating_hours' }, +    { 'iconName': 'standard:home', 'id': 'standard:home' }, +    { 'iconName': 'standard:household', 'id': 'standard:household' }, +    { 'iconName': 'standard:immunization', 'id': 'standard:immunization' }, +    { 'iconName': 'standard:individual', 'id': 'standard:individual' }, +    { 'iconName': 'standard:insights', 'id': 'standard:insights' }, +    { 'iconName': 'standard:instore_locations', 'id': 'standard:instore_locations' }, +    { 'iconName': 'standard:investment_account', 'id': 'standard:investment_account' }, +    { 'iconName': 'standard:invocable_action', 'id': 'standard:invocable_action' }, +    { 'iconName': 'standard:iot_context', 'id': 'standard:iot_context' }, +    { 'iconName': 'standard:iot_orchestrations', 'id': 'standard:iot_orchestrations' }, +    { 'iconName': 'standard:javascript_button', 'id': 'standard:javascript_button' }, +    { 'iconName': 'standard:job_family', 'id': 'standard:job_family' }, +    { 'iconName': 'standard:job_position', 'id': 'standard:job_position' }, +    { 'iconName': 'standard:job_profile', 'id': 'standard:job_profile' }, +    { 'iconName': 'standard:kanban', 'id': 'standard:kanban' }, +    { 'iconName': 'standard:key_dates', 'id': 'standard:key_dates' }, +    { 'iconName': 'standard:knowledge', 'id': 'standard:knowledge' }, +    { 'iconName': 'standard:lead', 'id': 'standard:lead' }, +    { 'iconName': 'standard:lead_insights', 'id': 'standard:lead_insights' }, +    { 'iconName': 'standard:lead_list', 'id': 'standard:lead_list' }, +    { 'iconName': 'standard:letterhead', 'id': 'standard:letterhead' }, +    { 'iconName': 'standard:lightning_component', 'id': 'standard:lightning_component' }, +    { 'iconName': 'standard:lightning_usage', 'id': 'standard:lightning_usage' }, +    { 'iconName': 'standard:link', 'id': 'standard:link' }, +    { 'iconName': 'standard:list_email', 'id': 'standard:list_email' }, +    { 'iconName': 'standard:live_chat', 'id': 'standard:live_chat' }, +    { 'iconName': 'standard:live_chat_visitor', 'id': 'standard:live_chat_visitor' }, +    { 'iconName': 'standard:location', 'id': 'standard:location' }, +    { 'iconName': 'standard:location_permit', 'id': 'standard:location_permit' }, +    { 'iconName': 'standard:log_a_call', 'id': 'standard:log_a_call' }, +    { 'iconName': 'standard:logging', 'id': 'standard:logging' }, +    { 'iconName': 'standard:loop', 'id': 'standard:loop' }, +    { 'iconName': 'standard:macros', 'id': 'standard:macros' }, +    { 'iconName': 'standard:maintenance_asset', 'id': 'standard:maintenance_asset' }, +    { 'iconName': 'standard:maintenance_plan', 'id': 'standard:maintenance_plan' }, +    { 'iconName': 'standard:maintenance_work_rule', 'id': 'standard:maintenance_work_rule' }, +    { 'iconName': 'standard:marketing_actions', 'id': 'standard:marketing_actions' }, +    { 'iconName': 'standard:medication_ingredient', 'id': 'standard:medication_ingredient' }, +    { 'iconName': 'standard:merge', 'id': 'standard:merge' }, +    { 'iconName': 'standard:messaging_conversation', 'id': 'standard:messaging_conversation' }, +    { 'iconName': 'standard:messaging_session', 'id': 'standard:messaging_session' }, +    { 'iconName': 'standard:messaging_user', 'id': 'standard:messaging_user' }, +    { 'iconName': 'standard:metrics', 'id': 'standard:metrics' }, +    { 'iconName': 'standard:multi_picklist', 'id': 'standard:multi_picklist' }, +    { 'iconName': 'standard:multi_select_checkbox', 'id': 'standard:multi_select_checkbox' }, +    { 'iconName': 'standard:news', 'id': 'standard:news' }, +    { 'iconName': 'standard:note', 'id': 'standard:note' }, +    { 'iconName': 'standard:number_input', 'id': 'standard:number_input' }, +    { 'iconName': 'standard:observation_component', 'id': 'standard:observation_component' }, +    { 'iconName': 'standard:omni_supervisor', 'id': 'standard:omni_supervisor' }, +    { 'iconName': 'standard:operating_hours', 'id': 'standard:operating_hours' }, +    { 'iconName': 'standard:opportunity', 'id': 'standard:opportunity' }, +    { 'iconName': 'standard:opportunity_contact_role', 'id': 'standard:opportunity_contact_role' }, +    { 'iconName': 'standard:opportunity_splits', 'id': 'standard:opportunity_splits' }, +    { 'iconName': 'standard:orchestrator', 'id': 'standard:orchestrator' }, +    { 'iconName': 'standard:order_item', 'id': 'standard:order_item' }, +    { 'iconName': 'standard:orders', 'id': 'standard:orders' }, +    { 'iconName': 'standard:outcome', 'id': 'standard:outcome' }, +    { 'iconName': 'standard:output', 'id': 'standard:output' }, +    { 'iconName': 'standard:partner_fund_allocation', 'id': 'standard:partner_fund_allocation' }, +    { 'iconName': 'standard:partner_fund_claim', 'id': 'standard:partner_fund_claim' }, +    { 'iconName': 'standard:partner_fund_request', 'id': 'standard:partner_fund_request' }, +    { 'iconName': 'standard:partner_marketing_budget', 'id': 'standard:partner_marketing_budget' }, +    { 'iconName': 'standard:partners', 'id': 'standard:partners' }, +    { 'iconName': 'standard:password', 'id': 'standard:password' }, +    { 'iconName': 'standard:past_chat', 'id': 'standard:past_chat' }, +    { 'iconName': 'standard:payment_gateway', 'id': 'standard:payment_gateway' }, +    { 'iconName': 'standard:people', 'id': 'standard:people' }, +    { 'iconName': 'standard:performance', 'id': 'standard:performance' }, +    { 'iconName': 'standard:person_account', 'id': 'standard:person_account' }, +    { 'iconName': 'standard:photo', 'id': 'standard:photo' }, +    { 'iconName': 'standard:picklist_choice', 'id': 'standard:picklist_choice' }, +    { 'iconName': 'standard:picklist_type', 'id': 'standard:picklist_type' }, +    { 'iconName': 'standard:planogram', 'id': 'standard:planogram' }, +    { 'iconName': 'standard:poll', 'id': 'standard:poll' }, +    { 'iconName': 'standard:portal', 'id': 'standard:portal' }, +    { 'iconName': 'standard:portal_roles', 'id': 'standard:portal_roles' }, +    { 'iconName': 'standard:portal_roles_and_subordinates', 'id': 'standard:portal_roles_and_subordinates' }, +    { 'iconName': 'standard:post', 'id': 'standard:post' }, +    { 'iconName': 'standard:practitioner_role', 'id': 'standard:practitioner_role' }, +    { 'iconName': 'standard:price_book_entries', 'id': 'standard:price_book_entries' }, +    { 'iconName': 'standard:price_books', 'id': 'standard:price_books' }, +    { 'iconName': 'standard:pricebook', 'id': 'standard:pricebook' }, +    { 'iconName': 'standard:pricing_workspace', 'id': 'standard:pricing_workspace' }, +    { 'iconName': 'standard:procedure', 'id': 'standard:procedure' }, +    { 'iconName': 'standard:procedure_detail', 'id': 'standard:procedure_detail' }, +    { 'iconName': 'standard:process', 'id': 'standard:process' }, +    { 'iconName': 'standard:process_exception', 'id': 'standard:process_exception' }, +    { 'iconName': 'standard:product', 'id': 'standard:product' }, +    { 'iconName': 'standard:product_consumed', 'id': 'standard:product_consumed' }, +    { 'iconName': 'standard:product_item', 'id': 'standard:product_item' }, +    { 'iconName': 'standard:product_item_transaction', 'id': 'standard:product_item_transaction' }, +    { 'iconName': 'standard:product_quantity_rules', 'id': 'standard:product_quantity_rules' }, +    { 'iconName': 'standard:product_request', 'id': 'standard:product_request' }, +    { 'iconName': 'standard:product_request_line_item', 'id': 'standard:product_request_line_item' }, +    { 'iconName': 'standard:product_required', 'id': 'standard:product_required' }, +    { 'iconName': 'standard:product_service_campaign', 'id': 'standard:product_service_campaign' }, +    { 'iconName': 'standard:product_service_campaign_item', 'id': 'standard:product_service_campaign_item' }, +    { 'iconName': 'standard:product_transfer', 'id': 'standard:product_transfer' }, +    { 'iconName': 'standard:product_warranty_term', 'id': 'standard:product_warranty_term' }, +    { 'iconName': 'standard:product_workspace', 'id': 'standard:product_workspace' }, +    { 'iconName': 'standard:products', 'id': 'standard:products' }, +    { 'iconName': 'standard:promotions', 'id': 'standard:promotions' }, +    { 'iconName': 'standard:propagation_policy', 'id': 'standard:propagation_policy' }, +    { 'iconName': 'standard:proposition', 'id': 'standard:proposition' }, +    { 'iconName': 'standard:question_best', 'id': 'standard:question_best' }, +    { 'iconName': 'standard:question_feed', 'id': 'standard:question_feed' }, +    { 'iconName': 'standard:queue', 'id': 'standard:queue' }, +    { 'iconName': 'standard:quick_text', 'id': 'standard:quick_text' }, +    { 'iconName': 'standard:quip', 'id': 'standard:quip' }, +    { 'iconName': 'standard:quip_sheet', 'id': 'standard:quip_sheet' }, +    { 'iconName': 'standard:quotes', 'id': 'standard:quotes' }, +    { 'iconName': 'standard:radio_button', 'id': 'standard:radio_button' }, +    { 'iconName': 'standard:read_receipts', 'id': 'standard:read_receipts' }, +    { 'iconName': 'standard:recent', 'id': 'standard:recent' }, +    { 'iconName': 'standard:recipe', 'id': 'standard:recipe' }, +    { 'iconName': 'standard:record', 'id': 'standard:record' }, +    { 'iconName': 'standard:record_create', 'id': 'standard:record_create' }, +    { 'iconName': 'standard:record_delete', 'id': 'standard:record_delete' }, +    { 'iconName': 'standard:record_lookup', 'id': 'standard:record_lookup' }, +    { 'iconName': 'standard:record_signature_task', 'id': 'standard:record_signature_task' }, +    { 'iconName': 'standard:record_update', 'id': 'standard:record_update' }, +    { 'iconName': 'standard:recycle_bin', 'id': 'standard:recycle_bin' }, +    { 'iconName': 'standard:related_list', 'id': 'standard:related_list' }, +    { 'iconName': 'standard:relationship', 'id': 'standard:relationship' }, +    { 'iconName': 'standard:reply_text', 'id': 'standard:reply_text' }, +    { 'iconName': 'standard:report', 'id': 'standard:report' }, +    { 'iconName': 'standard:resource_absence', 'id': 'standard:resource_absence' }, +    { 'iconName': 'standard:resource_capacity', 'id': 'standard:resource_capacity' }, +    { 'iconName': 'standard:resource_preference', 'id': 'standard:resource_preference' }, +    { 'iconName': 'standard:resource_skill', 'id': 'standard:resource_skill' }, +    { 'iconName': 'standard:restriction_policy', 'id': 'standard:restriction_policy' }, +    { 'iconName': 'standard:return_order', 'id': 'standard:return_order' }, +    { 'iconName': 'standard:return_order_line_item', 'id': 'standard:return_order_line_item' }, +    { 'iconName': 'standard:reward', 'id': 'standard:reward' }, +    { 'iconName': 'standard:rtc_presence', 'id': 'standard:rtc_presence' }, +    { 'iconName': 'standard:sales_cadence', 'id': 'standard:sales_cadence' }, +    { 'iconName': 'standard:sales_cadence_target', 'id': 'standard:sales_cadence_target' }, +    { 'iconName': 'standard:sales_channel', 'id': 'standard:sales_channel' }, +    { 'iconName': 'standard:sales_path', 'id': 'standard:sales_path' }, +    { 'iconName': 'standard:sales_value', 'id': 'standard:sales_value' }, +    { 'iconName': 'standard:salesforce_cms', 'id': 'standard:salesforce_cms' }, +    { 'iconName': 'standard:scan_card', 'id': 'standard:scan_card' }, +    { 'iconName': 'standard:schedule_objective', 'id': 'standard:schedule_objective' }, +    { 'iconName': 'standard:scheduling_constraint', 'id': 'standard:scheduling_constraint' }, +    { 'iconName': 'standard:scheduling_policy', 'id': 'standard:scheduling_policy' }, +    { 'iconName': 'standard:screen', 'id': 'standard:screen' }, +    { 'iconName': 'standard:search', 'id': 'standard:search' }, +    { 'iconName': 'standard:section', 'id': 'standard:section' }, +    { 'iconName': 'standard:segments', 'id': 'standard:segments' }, +    { 'iconName': 'standard:selling_model', 'id': 'standard:selling_model' }, +    { 'iconName': 'standard:serialized_product', 'id': 'standard:serialized_product' }, +    { 'iconName': 'standard:serialized_product_transaction', 'id': 'standard:serialized_product_transaction' }, +    { 'iconName': 'standard:service_appointment', 'id': 'standard:service_appointment' }, +    { 'iconName': 'standard:service_appointment_capacity_usage', 'id': 'standard:service_appointment_capacity_usage' }, +    { 'iconName': 'standard:service_contract', 'id': 'standard:service_contract' }, +    { 'iconName': 'standard:service_crew', 'id': 'standard:service_crew' }, +    { 'iconName': 'standard:service_crew_member', 'id': 'standard:service_crew_member' }, +    { 'iconName': 'standard:service_report', 'id': 'standard:service_report' }, +    { 'iconName': 'standard:service_request', 'id': 'standard:service_request' }, +    { 'iconName': 'standard:service_request_detail', 'id': 'standard:service_request_detail' }, +    { 'iconName': 'standard:service_resource', 'id': 'standard:service_resource' }, +    { 'iconName': 'standard:service_territory', 'id': 'standard:service_territory' }, +    { 'iconName': 'standard:service_territory_location', 'id': 'standard:service_territory_location' }, +    { 'iconName': 'standard:service_territory_member', 'id': 'standard:service_territory_member' }, +    { 'iconName': 'standard:service_territory_policy', 'id': 'standard:service_territory_policy' }, +    { 'iconName': 'standard:settings', 'id': 'standard:settings' }, +    { 'iconName': 'standard:shift', 'id': 'standard:shift' }, +    { 'iconName': 'standard:shift_pattern', 'id': 'standard:shift_pattern' }, +    { 'iconName': 'standard:shift_pattern_entry', 'id': 'standard:shift_pattern_entry' }, +    { 'iconName': 'standard:shift_preference', 'id': 'standard:shift_preference' }, +    { 'iconName': 'standard:shift_scheduling_operation', 'id': 'standard:shift_scheduling_operation' }, +    { 'iconName': 'standard:shift_template', 'id': 'standard:shift_template' }, +    { 'iconName': 'standard:shift_type', 'id': 'standard:shift_type' }, +    { 'iconName': 'standard:shipment', 'id': 'standard:shipment' }, +    { 'iconName': 'standard:skill', 'id': 'standard:skill' }, +    { 'iconName': 'standard:skill_entity', 'id': 'standard:skill_entity' }, +    { 'iconName': 'standard:skill_requirement', 'id': 'standard:skill_requirement' }, +    { 'iconName': 'standard:slider', 'id': 'standard:slider' }, +    { 'iconName': 'standard:sms', 'id': 'standard:sms' }, +    { 'iconName': 'standard:snippet', 'id': 'standard:snippet' }, +    { 'iconName': 'standard:snippets', 'id': 'standard:snippets' }, +    { 'iconName': 'standard:sobject', 'id': 'standard:sobject' }, +    { 'iconName': 'standard:sobject_collection', 'id': 'standard:sobject_collection' }, +    { 'iconName': 'standard:social', 'id': 'standard:social' }, +    { 'iconName': 'standard:solution', 'id': 'standard:solution' }, +    { 'iconName': 'standard:sort', 'id': 'standard:sort' }, +    { 'iconName': 'standard:sort_policy', 'id': 'standard:sort_policy' }, +    { 'iconName': 'standard:sossession', 'id': 'standard:sossession' }, +    { 'iconName': 'standard:stage', 'id': 'standard:stage' }, +    { 'iconName': 'standard:stage_collection', 'id': 'standard:stage_collection' }, +    { 'iconName': 'standard:steps', 'id': 'standard:steps' }, +    { 'iconName': 'standard:store', 'id': 'standard:store' }, +    { 'iconName': 'standard:store_group', 'id': 'standard:store_group' }, +    { 'iconName': 'standard:story', 'id': 'standard:story' }, +    { 'iconName': 'standard:strategy', 'id': 'standard:strategy' }, +    { 'iconName': 'standard:survey', 'id': 'standard:survey' }, +    { 'iconName': 'standard:swarm_request', 'id': 'standard:swarm_request' }, +    { 'iconName': 'standard:swarm_session', 'id': 'standard:swarm_session' }, +    { 'iconName': 'standard:system_and_global_variable', 'id': 'standard:system_and_global_variable' }, +    { 'iconName': 'standard:task', 'id': 'standard:task' }, +    { 'iconName': 'standard:task2', 'id': 'standard:task2' }, +    { 'iconName': 'standard:team_member', 'id': 'standard:team_member' }, +    { 'iconName': 'standard:template', 'id': 'standard:template' }, +    { 'iconName': 'standard:text', 'id': 'standard:text' }, +    { 'iconName': 'standard:text_template', 'id': 'standard:text_template' }, +    { 'iconName': 'standard:textarea', 'id': 'standard:textarea' }, +    { 'iconName': 'standard:textbox', 'id': 'standard:textbox' }, +    { 'iconName': 'standard:thanks', 'id': 'standard:thanks' }, +    { 'iconName': 'standard:thanks_loading', 'id': 'standard:thanks_loading' }, +    { 'iconName': 'standard:timesheet', 'id': 'standard:timesheet' }, +    { 'iconName': 'standard:timesheet_entry', 'id': 'standard:timesheet_entry' }, +    { 'iconName': 'standard:timeslot', 'id': 'standard:timeslot' }, +    { 'iconName': 'standard:today', 'id': 'standard:today' }, +    { 'iconName': 'standard:toggle', 'id': 'standard:toggle' }, +    { 'iconName': 'standard:topic', 'id': 'standard:topic' }, +    { 'iconName': 'standard:topic2', 'id': 'standard:topic2' }, +    { 'iconName': 'standard:trailhead', 'id': 'standard:trailhead' }, +    { 'iconName': 'standard:trailhead_alt', 'id': 'standard:trailhead_alt' }, +    { 'iconName': 'standard:travel_mode', 'id': 'standard:travel_mode' }, +    { 'iconName': 'standard:unmatched', 'id': 'standard:unmatched' }, +    { 'iconName': 'standard:user', 'id': 'standard:user' }, +    { 'iconName': 'standard:user_role', 'id': 'standard:user_role' }, +    { 'iconName': 'standard:variable', 'id': 'standard:variable' }, +    { 'iconName': 'standard:variation_attribute_setup', 'id': 'standard:variation_attribute_setup' }, +    { 'iconName': 'standard:variation_products', 'id': 'standard:variation_products' }, +    { 'iconName': 'standard:video', 'id': 'standard:video' }, +    { 'iconName': 'standard:visit_templates', 'id': 'standard:visit_templates' }, +    { 'iconName': 'standard:visits', 'id': 'standard:visits' }, +    { 'iconName': 'standard:visualforce_page', 'id': 'standard:visualforce_page' }, +    { 'iconName': 'standard:voice_call', 'id': 'standard:voice_call' }, +    { 'iconName': 'standard:waits', 'id': 'standard:waits' }, +    { 'iconName': 'standard:warranty_term', 'id': 'standard:warranty_term' }, +    { 'iconName': 'standard:webcart', 'id': 'standard:webcart' }, +    { 'iconName': 'standard:work_capacity_limit', 'id': 'standard:work_capacity_limit' }, +    { 'iconName': 'standard:work_capacity_usage', 'id': 'standard:work_capacity_usage' }, +    { 'iconName': 'standard:work_contract', 'id': 'standard:work_contract' }, +    { 'iconName': 'standard:work_forecast', 'id': 'standard:work_forecast' }, +    { 'iconName': 'standard:work_order', 'id': 'standard:work_order' }, +    { 'iconName': 'standard:work_order_item', 'id': 'standard:work_order_item' }, +    { 'iconName': 'standard:work_plan', 'id': 'standard:work_plan' }, +    { 'iconName': 'standard:work_plan_rule', 'id': 'standard:work_plan_rule' }, +    { 'iconName': 'standard:work_plan_template', 'id': 'standard:work_plan_template' }, +    { 'iconName': 'standard:work_plan_template_entry', 'id': 'standard:work_plan_template_entry' }, +    { 'iconName': 'standard:work_queue', 'id': 'standard:work_queue' }, +    { 'iconName': 'standard:work_step', 'id': 'standard:work_step' }, +    { 'iconName': 'standard:work_step_template', 'id': 'standard:work_step_template' }, +    { 'iconName': 'standard:work_type', 'id': 'standard:work_type' }, +    { 'iconName': 'standard:work_type_group', 'id': 'standard:work_type_group' } +] + +const UTILITY_ICONS = [ + { 'iconName': 'utility:activity', 'id': 'utility:activity' }, + { 'iconName': 'utility:ad_set', 'id': 'utility:ad_set' }, + { 'iconName': 'utility:add', 'id': 'utility:add' }, + { 'iconName': 'utility:adduser', 'id': 'utility:adduser' }, + { 'iconName': 'utility:adjust_value', 'id': 'utility:adjust_value' }, + { 'iconName': 'utility:advanced_function', 'id': 'utility:advanced_function' }, + { 'iconName': 'utility:advertising', 'id': 'utility:advertising' }, + { 'iconName': 'utility:agent_home', 'id': 'utility:agent_home' }, + { 'iconName': 'utility:agent_session', 'id': 'utility:agent_session' }, + { 'iconName': 'utility:aggregation_policy', 'id': 'utility:aggregation_policy' }, + { 'iconName': 'utility:alert', 'id': 'utility:alert' }, + { 'iconName': 'utility:all', 'id': 'utility:all' }, + { 'iconName': 'utility:anchor', 'id': 'utility:anchor' }, + { 'iconName': 'utility:animal_and_nature', 'id': 'utility:animal_and_nature' }, + { 'iconName': 'utility:announcement', 'id': 'utility:announcement' }, + { 'iconName': 'utility:answer', 'id': 'utility:answer' }, + { 'iconName': 'utility:answered_twice', 'id': 'utility:answered_twice' }, + { 'iconName': 'utility:anywhere_alert', 'id': 'utility:anywhere_alert' }, + { 'iconName': 'utility:anywhere_chat', 'id': 'utility:anywhere_chat' }, + { 'iconName': 'utility:apex', 'id': 'utility:apex' }, + { 'iconName': 'utility:apex_plugin', 'id': 'utility:apex_plugin' }, + { 'iconName': 'utility:approval', 'id': 'utility:approval' }, + { 'iconName': 'utility:apps', 'id': 'utility:apps' }, + { 'iconName': 'utility:archive', 'id': 'utility:archive' }, + { 'iconName': 'utility:arrow_bottom', 'id': 'utility:arrow_bottom' }, + { 'iconName': 'utility:arrow_left', 'id': 'utility:arrow_left' }, + { 'iconName': 'utility:arrow_right', 'id': 'utility:arrow_right' }, + { 'iconName': 'utility:arrow_top', 'id': 'utility:arrow_top' }, + { 'iconName': 'utility:arrowdown', 'id': 'utility:arrowdown' }, + { 'iconName': 'utility:arrowup', 'id': 'utility:arrowup' }, + { 'iconName': 'utility:asset_warranty', 'id': 'utility:asset_warranty' }, + { 'iconName': 'utility:assignment', 'id': 'utility:assignment' }, + { 'iconName': 'utility:attach', 'id': 'utility:attach' }, + { 'iconName': 'utility:automate', 'id': 'utility:automate' }, + { 'iconName': 'utility:away', 'id': 'utility:away' }, + { 'iconName': 'utility:back', 'id': 'utility:back' }, + { 'iconName': 'utility:ban', 'id': 'utility:ban' }, + { 'iconName': 'utility:block_visitor', 'id': 'utility:block_visitor' }, + { 'iconName': 'utility:bold', 'id': 'utility:bold' }, + { 'iconName': 'utility:bookmark', 'id': 'utility:bookmark' }, + { 'iconName': 'utility:bottom_align', 'id': 'utility:bottom_align' }, + { 'iconName': 'utility:breadcrumbs', 'id': 'utility:breadcrumbs' }, + { 'iconName': 'utility:broadcast', 'id': 'utility:broadcast' }, + { 'iconName': 'utility:brush', 'id': 'utility:brush' }, + { 'iconName': 'utility:bucket', 'id': 'utility:bucket' }, + { 'iconName': 'utility:bug', 'id': 'utility:bug' }, + { 'iconName': 'utility:builder', 'id': 'utility:builder' }, + { 'iconName': 'utility:bundle_config', 'id': 'utility:bundle_config' }, + { 'iconName': 'utility:bundle_policy', 'id': 'utility:bundle_policy' }, + { 'iconName': 'utility:button_choice', 'id': 'utility:button_choice' }, + { 'iconName': 'utility:calculated_insights', 'id': 'utility:calculated_insights' }, + { 'iconName': 'utility:call', 'id': 'utility:call' }, + { 'iconName': 'utility:campaign', 'id': 'utility:campaign' }, + { 'iconName': 'utility:cancel_file_request', 'id': 'utility:cancel_file_request' }, + { 'iconName': 'utility:cancel_transfer', 'id': 'utility:cancel_transfer' }, + { 'iconName': 'utility:capacity_plan', 'id': 'utility:capacity_plan' }, + { 'iconName': 'utility:capslock', 'id': 'utility:capslock' }, + { 'iconName': 'utility:cart', 'id': 'utility:cart' }, + { 'iconName': 'utility:case', 'id': 'utility:case' }, + { 'iconName': 'utility:cases', 'id': 'utility:cases' }, + { 'iconName': 'utility:center_align', 'id': 'utility:center_align' }, + { 'iconName': 'utility:center_align_text', 'id': 'utility:center_align_text' }, + { 'iconName': 'utility:change_owner', 'id': 'utility:change_owner' }, + { 'iconName': 'utility:change_record_type', 'id': 'utility:change_record_type' }, + { 'iconName': 'utility:chart', 'id': 'utility:chart' }, + { 'iconName': 'utility:chat', 'id': 'utility:chat' }, + { 'iconName': 'utility:check', 'id': 'utility:check' }, + { 'iconName': 'utility:checkin', 'id': 'utility:checkin' }, + { 'iconName': 'utility:checkout', 'id': 'utility:checkout' }, + { 'iconName': 'utility:chevrondown', 'id': 'utility:chevrondown' }, + { 'iconName': 'utility:chevronleft', 'id': 'utility:chevronleft' }, + { 'iconName': 'utility:chevronright', 'id': 'utility:chevronright' }, + { 'iconName': 'utility:chevronup', 'id': 'utility:chevronup' }, + { 'iconName': 'utility:choice', 'id': 'utility:choice' }, + { 'iconName': 'utility:classic_interface', 'id': 'utility:classic_interface' }, + { 'iconName': 'utility:clear', 'id': 'utility:clear' }, + { 'iconName': 'utility:clock', 'id': 'utility:clock' }, + { 'iconName': 'utility:close', 'id': 'utility:close' }, + { 'iconName': 'utility:collapse_all', 'id': 'utility:collapse_all' }, + { 'iconName': 'utility:collection', 'id': 'utility:collection' }, + { 'iconName': 'utility:collection_variable', 'id': 'utility:collection_variable' }, + { 'iconName': 'utility:color_swatch', 'id': 'utility:color_swatch' }, + { 'iconName': 'utility:comments', 'id': 'utility:comments' }, + { 'iconName': 'utility:company', 'id': 'utility:company' }, + { 'iconName': 'utility:component_customization', 'id': 'utility:component_customization' }, + { 'iconName': 'utility:connected_apps', 'id': 'utility:connected_apps' }, + { 'iconName': 'utility:constant', 'id': 'utility:constant' }, + { 'iconName': 'utility:contact_request', 'id': 'utility:contact_request' }, + { 'iconName': 'utility:contract', 'id': 'utility:contract' }, + { 'iconName': 'utility:contract_alt', 'id': 'utility:contract_alt' }, + { 'iconName': 'utility:copy', 'id': 'utility:copy' }, + { 'iconName': 'utility:copy_to_clipboard', 'id': 'utility:copy_to_clipboard' }, + { 'iconName': 'utility:crossfilter', 'id': 'utility:crossfilter' }, + { 'iconName': 'utility:currency', 'id': 'utility:currency' }, + { 'iconName': 'utility:currency_input', 'id': 'utility:currency_input' }, + { 'iconName': 'utility:custom_apps', 'id': 'utility:custom_apps' }, + { 'iconName': 'utility:cut', 'id': 'utility:cut' }, + { 'iconName': 'utility:dash', 'id': 'utility:dash' }, + { 'iconName': 'utility:data_mapping', 'id': 'utility:data_mapping' }, + { 'iconName': 'utility:database', 'id': 'utility:database' }, + { 'iconName': 'utility:datadotcom', 'id': 'utility:datadotcom' }, + { 'iconName': 'utility:date_input', 'id': 'utility:date_input' }, + { 'iconName': 'utility:date_time', 'id': 'utility:date_time' }, + { 'iconName': 'utility:dayview', 'id': 'utility:dayview' }, + { 'iconName': 'utility:delete', 'id': 'utility:delete' }, + { 'iconName': 'utility:deprecate', 'id': 'utility:deprecate' }, + { 'iconName': 'utility:description', 'id': 'utility:description' }, + { 'iconName': 'utility:desktop', 'id': 'utility:desktop' }, + { 'iconName': 'utility:desktop_and_phone', 'id': 'utility:desktop_and_phone' }, + { 'iconName': 'utility:desktop_console', 'id': 'utility:desktop_console' }, + { 'iconName': 'utility:dialing', 'id': 'utility:dialing' }, + { 'iconName': 'utility:diamond', 'id': 'utility:diamond' }, + { 'iconName': 'utility:dislike', 'id': 'utility:dislike' }, + { 'iconName': 'utility:display_rich_text', 'id': 'utility:display_rich_text' }, + { 'iconName': 'utility:display_text', 'id': 'utility:display_text' }, + { 'iconName': 'utility:dock_panel', 'id': 'utility:dock_panel' }, + { 'iconName': 'utility:down', 'id': 'utility:down' }, + { 'iconName': 'utility:download', 'id': 'utility:download' }, + { 'iconName': 'utility:drag', 'id': 'utility:drag' }, + { 'iconName': 'utility:drag_and_drop', 'id': 'utility:drag_and_drop' }, + { 'iconName': 'utility:duration_downscale', 'id': 'utility:duration_downscale' }, + { 'iconName': 'utility:dynamic_record_choice', 'id': 'utility:dynamic_record_choice' }, + { 'iconName': 'utility:edit', 'id': 'utility:edit' }, + { 'iconName': 'utility:edit_form', 'id': 'utility:edit_form' }, + { 'iconName': 'utility:education', 'id': 'utility:education' }, + { 'iconName': 'utility:einstein', 'id': 'utility:einstein' }, + { 'iconName': 'utility:email', 'id': 'utility:email' }, + { 'iconName': 'utility:email_open', 'id': 'utility:email_open' }, + { 'iconName': 'utility:emoji', 'id': 'utility:emoji' }, + { 'iconName': 'utility:end_call', 'id': 'utility:end_call' }, + { 'iconName': 'utility:end_chat', 'id': 'utility:end_chat' }, + { 'iconName': 'utility:end_messaging_session', 'id': 'utility:end_messaging_session' }, + { 'iconName': 'utility:engage', 'id': 'utility:engage' }, + { 'iconName': 'utility:enter', 'id': 'utility:enter' }, + { 'iconName': 'utility:erect_window', 'id': 'utility:erect_window' }, + { 'iconName': 'utility:error', 'id': 'utility:error' }, + { 'iconName': 'utility:event', 'id': 'utility:event' }, + { 'iconName': 'utility:event_ext', 'id': 'utility:event_ext' }, + { 'iconName': 'utility:events', 'id': 'utility:events' }, + { 'iconName': 'utility:expand', 'id': 'utility:expand' }, + { 'iconName': 'utility:expand_all', 'id': 'utility:expand_all' }, + { 'iconName': 'utility:expand_alt', 'id': 'utility:expand_alt' }, + { 'iconName': 'utility:fallback', 'id': 'utility:fallback' }, + { 'iconName': 'utility:favorite', 'id': 'utility:favorite' }, + { 'iconName': 'utility:feed', 'id': 'utility:feed' }, + { 'iconName': 'utility:file', 'id': 'utility:file' }, + { 'iconName': 'utility:filter', 'id': 'utility:filter' }, + { 'iconName': 'utility:filter_criteria', 'id': 'utility:filter_criteria' }, + { 'iconName': 'utility:filter_criteria_rule', 'id': 'utility:filter_criteria_rule' }, + { 'iconName': 'utility:filterList', 'id': 'utility:filterList' }, + { 'iconName': 'utility:flow', 'id': 'utility:flow' }, + { 'iconName': 'utility:flow_alt', 'id': 'utility:flow_alt' }, + { 'iconName': 'utility:food_and_drink', 'id': 'utility:food_and_drink' }, + { 'iconName': 'utility:form', 'id': 'utility:form' }, + { 'iconName': 'utility:formula', 'id': 'utility:formula' }, + { 'iconName': 'utility:forward', 'id': 'utility:forward' }, + { 'iconName': 'utility:forward_up', 'id': 'utility:forward_up' }, + { 'iconName': 'utility:freeze_column', 'id': 'utility:freeze_column' }, + { 'iconName': 'utility:frozen', 'id': 'utility:frozen' }, + { 'iconName': 'utility:fulfillment_order', 'id': 'utility:fulfillment_order' }, + { 'iconName': 'utility:full_width_view', 'id': 'utility:full_width_view' }, + { 'iconName': 'utility:global_constant', 'id': 'utility:global_constant' }, + { 'iconName': 'utility:graph', 'id': 'utility:graph' }, + { 'iconName': 'utility:groups', 'id': 'utility:groups' }, + { 'iconName': 'utility:help', 'id': 'utility:help' }, + { 'iconName': 'utility:help_center', 'id': 'utility:help_center' }, + { 'iconName': 'utility:help_doc_ext', 'id': 'utility:help_doc_ext' }, + { 'iconName': 'utility:hide', 'id': 'utility:hide' }, + { 'iconName': 'utility:hide_mobile', 'id': 'utility:hide_mobile' }, + { 'iconName': 'utility:hierarchy', 'id': 'utility:hierarchy' }, + { 'iconName': 'utility:high_velocity_sales', 'id': 'utility:high_velocity_sales' }, + { 'iconName': 'utility:holiday_operating_hours', 'id': 'utility:holiday_operating_hours' }, + { 'iconName': 'utility:home', 'id': 'utility:home' }, + { 'iconName': 'utility:identity', 'id': 'utility:identity' }, + { 'iconName': 'utility:image', 'id': 'utility:image' }, + { 'iconName': 'utility:in_app_assistant', 'id': 'utility:in_app_assistant' }, + { 'iconName': 'utility:inbox', 'id': 'utility:inbox' }, + { 'iconName': 'utility:incoming_call', 'id': 'utility:incoming_call' }, + { 'iconName': 'utility:info', 'id': 'utility:info' }, + { 'iconName': 'utility:info_alt', 'id': 'utility:info_alt' }, + { 'iconName': 'utility:insert_tag_field', 'id': 'utility:insert_tag_field' }, + { 'iconName': 'utility:insert_template', 'id': 'utility:insert_template' }, + { 'iconName': 'utility:inspector_panel', 'id': 'utility:inspector_panel' }, + { 'iconName': 'utility:internal_share', 'id': 'utility:internal_share' }, + { 'iconName': 'utility:italic', 'id': 'utility:italic' }, + { 'iconName': 'utility:jump_to_bottom', 'id': 'utility:jump_to_bottom' }, + { 'iconName': 'utility:jump_to_left', 'id': 'utility:jump_to_left' }, + { 'iconName': 'utility:jump_to_right', 'id': 'utility:jump_to_right' }, + { 'iconName': 'utility:jump_to_top', 'id': 'utility:jump_to_top' }, + { 'iconName': 'utility:justify_text', 'id': 'utility:justify_text' }, + { 'iconName': 'utility:kanban', 'id': 'utility:kanban' }, + { 'iconName': 'utility:key', 'id': 'utility:key' }, + { 'iconName': 'utility:key_dates', 'id': 'utility:key_dates' }, + { 'iconName': 'utility:keyboard_dismiss', 'id': 'utility:keyboard_dismiss' }, + { 'iconName': 'utility:keypad', 'id': 'utility:keypad' }, + { 'iconName': 'utility:knowledge_base', 'id': 'utility:knowledge_base' }, + { 'iconName': 'utility:layers', 'id': 'utility:layers' }, + { 'iconName': 'utility:layout', 'id': 'utility:layout' }, + { 'iconName': 'utility:leave_conference', 'id': 'utility:leave_conference' }, + { 'iconName': 'utility:left', 'id': 'utility:left' }, + { 'iconName': 'utility:left_align', 'id': 'utility:left_align' }, + { 'iconName': 'utility:left_align_text', 'id': 'utility:left_align_text' }, + { 'iconName': 'utility:level_down', 'id': 'utility:level_down' }, + { 'iconName': 'utility:level_up', 'id': 'utility:level_up' }, + { 'iconName': 'utility:light_bulb', 'id': 'utility:light_bulb' }, + { 'iconName': 'utility:lightning_extension', 'id': 'utility:lightning_extension' }, + { 'iconName': 'utility:lightning_inspector', 'id': 'utility:lightning_inspector' }, + { 'iconName': 'utility:like', 'id': 'utility:like' }, + { 'iconName': 'utility:link', 'id': 'utility:link' }, + { 'iconName': 'utility:linked', 'id': 'utility:linked' }, + { 'iconName': 'utility:list', 'id': 'utility:list' }, + { 'iconName': 'utility:listen', 'id': 'utility:listen' }, + { 'iconName': 'utility:live_message', 'id': 'utility:live_message' }, + { 'iconName': 'utility:location', 'id': 'utility:location' }, + { 'iconName': 'utility:location_permit', 'id': 'utility:location_permit' }, + { 'iconName': 'utility:lock', 'id': 'utility:lock' }, + { 'iconName': 'utility:locker_service_api_viewer', 'id': 'utility:locker_service_api_viewer' }, + { 'iconName': 'utility:locker_service_console', 'id': 'utility:locker_service_console' }, + { 'iconName': 'utility:log_a_call', 'id': 'utility:log_a_call' }, + { 'iconName': 'utility:logout', 'id': 'utility:logout' }, + { 'iconName': 'utility:loop', 'id': 'utility:loop' }, + { 'iconName': 'utility:lower_flag', 'id': 'utility:lower_flag' }, + { 'iconName': 'utility:macros', 'id': 'utility:macros' }, + { 'iconName': 'utility:magicwand', 'id': 'utility:magicwand' }, + { 'iconName': 'utility:mark_all_as_read', 'id': 'utility:mark_all_as_read' }, + { 'iconName': 'utility:matrix', 'id': 'utility:matrix' }, + { 'iconName': 'utility:meet_content_source', 'id': 'utility:meet_content_source' }, + { 'iconName': 'utility:meet_focus_content', 'id': 'utility:meet_focus_content' }, + { 'iconName': 'utility:meet_focus_equal', 'id': 'utility:meet_focus_equal' }, + { 'iconName': 'utility:meet_focus_presenter', 'id': 'utility:meet_focus_presenter' }, + { 'iconName': 'utility:meet_present_panel', 'id': 'utility:meet_present_panel' }, + { 'iconName': 'utility:merge', 'id': 'utility:merge' }, + { 'iconName': 'utility:merge_field', 'id': 'utility:merge_field' }, + { 'iconName': 'utility:metrics', 'id': 'utility:metrics' }, + { 'iconName': 'utility:middle_align', 'id': 'utility:middle_align' }, + { 'iconName': 'utility:minimize_window', 'id': 'utility:minimize_window' }, + { 'iconName': 'utility:missed_call', 'id': 'utility:missed_call' }, + { 'iconName': 'utility:money', 'id': 'utility:money' }, + { 'iconName': 'utility:moneybag', 'id': 'utility:moneybag' }, + { 'iconName': 'utility:monthlyview', 'id': 'utility:monthlyview' }, + { 'iconName': 'utility:move', 'id': 'utility:move' }, + { 'iconName': 'utility:multi_picklist', 'id': 'utility:multi_picklist' }, + { 'iconName': 'utility:multi_select_checkbox', 'id': 'utility:multi_select_checkbox' }, + { 'iconName': 'utility:muted', 'id': 'utility:muted' }, + { 'iconName': 'utility:new', 'id': 'utility:new' }, + { 'iconName': 'utility:new_direct_message', 'id': 'utility:new_direct_message' }, + { 'iconName': 'utility:new_window', 'id': 'utility:new_window' }, + { 'iconName': 'utility:news', 'id': 'utility:news' }, + { 'iconName': 'utility:note', 'id': 'utility:note' }, + { 'iconName': 'utility:notebook', 'id': 'utility:notebook' }, + { 'iconName': 'utility:notification', 'id': 'utility:notification' }, + { 'iconName': 'utility:number_input', 'id': 'utility:number_input' }, + { 'iconName': 'utility:office365', 'id': 'utility:office365' }, + { 'iconName': 'utility:offline', 'id': 'utility:offline' }, + { 'iconName': 'utility:offline_briefcase', 'id': 'utility:offline_briefcase' }, + { 'iconName': 'utility:offline_cached', 'id': 'utility:offline_cached' }, + { 'iconName': 'utility:omni_channel', 'id': 'utility:omni_channel' }, + { 'iconName': 'utility:open', 'id': 'utility:open' }, + { 'iconName': 'utility:open_folder', 'id': 'utility:open_folder' }, + { 'iconName': 'utility:opened_folder', 'id': 'utility:opened_folder' }, + { 'iconName': 'utility:orchestrator', 'id': 'utility:orchestrator' }, + { 'iconName': 'utility:org_chart', 'id': 'utility:org_chart' }, + { 'iconName': 'utility:outbound_call', 'id': 'utility:outbound_call' }, + { 'iconName': 'utility:outcome', 'id': 'utility:outcome' }, + { 'iconName': 'utility:overflow', 'id': 'utility:overflow' }, + { 'iconName': 'utility:package', 'id': 'utility:package' }, + { 'iconName': 'utility:package_org', 'id': 'utility:package_org' }, + { 'iconName': 'utility:package_org_beta', 'id': 'utility:package_org_beta' }, + { 'iconName': 'utility:page', 'id': 'utility:page' }, + { 'iconName': 'utility:palette', 'id': 'utility:palette' }, + { 'iconName': 'utility:password', 'id': 'utility:password' }, + { 'iconName': 'utility:paste', 'id': 'utility:paste' }, + { 'iconName': 'utility:pause', 'id': 'utility:pause' }, + { 'iconName': 'utility:pause_alt', 'id': 'utility:pause_alt' }, + { 'iconName': 'utility:payment_gateway', 'id': 'utility:payment_gateway' }, + { 'iconName': 'utility:pdf_ext', 'id': 'utility:pdf_ext' }, + { 'iconName': 'utility:people', 'id': 'utility:people' }, + { 'iconName': 'utility:percent', 'id': 'utility:percent' }, + { 'iconName': 'utility:phone_landscape', 'id': 'utility:phone_landscape' }, + { 'iconName': 'utility:phone_portrait', 'id': 'utility:phone_portrait' }, + { 'iconName': 'utility:photo', 'id': 'utility:photo' }, + { 'iconName': 'utility:picklist', 'id': 'utility:picklist' }, + { 'iconName': 'utility:picklist_choice', 'id': 'utility:picklist_choice' }, + { 'iconName': 'utility:picklist_type', 'id': 'utility:picklist_type' }, + { 'iconName': 'utility:pin', 'id': 'utility:pin' }, + { 'iconName': 'utility:pinned', 'id': 'utility:pinned' }, + { 'iconName': 'utility:planning_poker', 'id': 'utility:planning_poker' }, + { 'iconName': 'utility:play', 'id': 'utility:play' }, + { 'iconName': 'utility:podcast_webinar', 'id': 'utility:podcast_webinar' }, + { 'iconName': 'utility:pop_in', 'id': 'utility:pop_in' }, + { 'iconName': 'utility:power', 'id': 'utility:power' }, + { 'iconName': 'utility:preview', 'id': 'utility:preview' }, + { 'iconName': 'utility:price_book_entries', 'id': 'utility:price_book_entries' }, + { 'iconName': 'utility:price_books', 'id': 'utility:price_books' }, + { 'iconName': 'utility:pricing_workspace', 'id': 'utility:pricing_workspace' }, + { 'iconName': 'utility:print', 'id': 'utility:print' }, + { 'iconName': 'utility:priority', 'id': 'utility:priority' }, + { 'iconName': 'utility:privately_shared', 'id': 'utility:privately_shared' }, + { 'iconName': 'utility:process', 'id': 'utility:process' }, + { 'iconName': 'utility:product_quantity_rules', 'id': 'utility:product_quantity_rules' }, + { 'iconName': 'utility:product_service_campaign', 'id': 'utility:product_service_campaign' }, + { 'iconName': 'utility:product_service_campaign_item', 'id': 'utility:product_service_campaign_item' }, + { 'iconName': 'utility:product_warranty_term', 'id': 'utility:product_warranty_term' }, + { 'iconName': 'utility:product_workspace', 'id': 'utility:product_workspace' }, + { 'iconName': 'utility:products', 'id': 'utility:products' }, + { 'iconName': 'utility:profile', 'id': 'utility:profile' }, + { 'iconName': 'utility:promotions', 'id': 'utility:promotions' }, + { 'iconName': 'utility:prompt', 'id': 'utility:prompt' }, + { 'iconName': 'utility:prompt_edit', 'id': 'utility:prompt_edit' }, + { 'iconName': 'utility:propagation_policy', 'id': 'utility:propagation_policy' }, + { 'iconName': 'utility:push', 'id': 'utility:push' }, + { 'iconName': 'utility:puzzle', 'id': 'utility:puzzle' }, + { 'iconName': 'utility:question', 'id': 'utility:question' }, + { 'iconName': 'utility:question_mark', 'id': 'utility:question_mark' }, + { 'iconName': 'utility:questions_and_answers', 'id': 'utility:questions_and_answers' }, + { 'iconName': 'utility:quick_text', 'id': 'utility:quick_text' }, + { 'iconName': 'utility:quip', 'id': 'utility:quip' }, + { 'iconName': 'utility:quotation_marks', 'id': 'utility:quotation_marks' }, + { 'iconName': 'utility:quote', 'id': 'utility:quote' }, + { 'iconName': 'utility:radio_button', 'id': 'utility:radio_button' }, + { 'iconName': 'utility:rating', 'id': 'utility:rating' }, + { 'iconName': 'utility:reassign', 'id': 'utility:reassign' }, + { 'iconName': 'utility:recipe', 'id': 'utility:recipe' }, + { 'iconName': 'utility:record', 'id': 'utility:record' }, + { 'iconName': 'utility:record_create', 'id': 'utility:record_create' }, + { 'iconName': 'utility:record_delete', 'id': 'utility:record_delete' }, + { 'iconName': 'utility:record_lookup', 'id': 'utility:record_lookup' }, + { 'iconName': 'utility:record_update', 'id': 'utility:record_update' }, + { 'iconName': 'utility:recurring_exception', 'id': 'utility:recurring_exception' }, + { 'iconName': 'utility:recycle_bin_empty', 'id': 'utility:recycle_bin_empty' }, + { 'iconName': 'utility:recycle_bin_full', 'id': 'utility:recycle_bin_full' }, + { 'iconName': 'utility:redo', 'id': 'utility:redo' }, + { 'iconName': 'utility:refresh', 'id': 'utility:refresh' }, + { 'iconName': 'utility:relate', 'id': 'utility:relate' }, + { 'iconName': 'utility:reminder', 'id': 'utility:reminder' }, + { 'iconName': 'utility:remove_formatting', 'id': 'utility:remove_formatting' }, + { 'iconName': 'utility:remove_link', 'id': 'utility:remove_link' }, + { 'iconName': 'utility:replace', 'id': 'utility:replace' }, + { 'iconName': 'utility:reply', 'id': 'utility:reply' }, + { 'iconName': 'utility:reply_all', 'id': 'utility:reply_all' }, + { 'iconName': 'utility:report_issue', 'id': 'utility:report_issue' }, + { 'iconName': 'utility:reset_password', 'id': 'utility:reset_password' }, + { 'iconName': 'utility:resource_absence', 'id': 'utility:resource_absence' }, + { 'iconName': 'utility:resource_capacity', 'id': 'utility:resource_capacity' }, + { 'iconName': 'utility:resource_territory', 'id': 'utility:resource_territory' }, + { 'iconName': 'utility:restriction_policy', 'id': 'utility:restriction_policy' }, + { 'iconName': 'utility:retail_execution', 'id': 'utility:retail_execution' }, + { 'iconName': 'utility:retweet', 'id': 'utility:retweet' }, + { 'iconName': 'utility:ribbon', 'id': 'utility:ribbon' }, + { 'iconName': 'utility:richtextbulletedlist', 'id': 'utility:richtextbulletedlist' }, + { 'iconName': 'utility:richtextindent', 'id': 'utility:richtextindent' }, + { 'iconName': 'utility:richtextnumberedlist', 'id': 'utility:richtextnumberedlist' }, + { 'iconName': 'utility:richtextoutdent', 'id': 'utility:richtextoutdent' }, + { 'iconName': 'utility:right', 'id': 'utility:right' }, + { 'iconName': 'utility:right_align', 'id': 'utility:right_align' }, + { 'iconName': 'utility:right_align_text', 'id': 'utility:right_align_text' }, + { 'iconName': 'utility:rotate', 'id': 'utility:rotate' }, + { 'iconName': 'utility:routing_offline', 'id': 'utility:routing_offline' }, + { 'iconName': 'utility:rows', 'id': 'utility:rows' }, + { 'iconName': 'utility:rules', 'id': 'utility:rules' }, + { 'iconName': 'utility:salesforce_page', 'id': 'utility:salesforce_page' }, + { 'iconName': 'utility:salesforce1', 'id': 'utility:salesforce1' }, + { 'iconName': 'utility:save', 'id': 'utility:save' }, + { 'iconName': 'utility:screen', 'id': 'utility:screen' }, + { 'iconName': 'utility:search', 'id': 'utility:search' }, + { 'iconName': 'utility:section', 'id': 'utility:section' }, + { 'iconName': 'utility:send', 'id': 'utility:send' }, + { 'iconName': 'utility:sentiment_negative', 'id': 'utility:sentiment_negative' }, + { 'iconName': 'utility:sentiment_neutral', 'id': 'utility:sentiment_neutral' }, + { 'iconName': 'utility:serialized_product', 'id': 'utility:serialized_product' }, + { 'iconName': 'utility:serialized_product_transaction', 'id': 'utility:serialized_product_transaction' }, + { 'iconName': 'utility:service_territory_policy', 'id': 'utility:service_territory_policy' }, + { 'iconName': 'utility:settings', 'id': 'utility:settings' }, + { 'iconName': 'utility:setup', 'id': 'utility:setup' }, + { 'iconName': 'utility:setup_assistant_guide', 'id': 'utility:setup_assistant_guide' }, + { 'iconName': 'utility:setup_modal', 'id': 'utility:setup_modal' }, + { 'iconName': 'utility:share', 'id': 'utility:share' }, + { 'iconName': 'utility:share_file', 'id': 'utility:share_file' }, + { 'iconName': 'utility:share_mobile', 'id': 'utility:share_mobile' }, + { 'iconName': 'utility:share_post', 'id': 'utility:share_post' }, + { 'iconName': 'utility:shield', 'id': 'utility:shield' }, + { 'iconName': 'utility:shift_pattern', 'id': 'utility:shift_pattern' }, + { 'iconName': 'utility:shift_pattern_entry', 'id': 'utility:shift_pattern_entry' }, + { 'iconName': 'utility:shift_scheduling_operation', 'id': 'utility:shift_scheduling_operation' }, + { 'iconName': 'utility:shift_ui', 'id': 'utility:shift_ui' }, + { 'iconName': 'utility:shopping_bag', 'id': 'utility:shopping_bag' }, + { 'iconName': 'utility:shortcuts', 'id': 'utility:shortcuts' }, + { 'iconName': 'utility:side_list', 'id': 'utility:side_list' }, + { 'iconName': 'utility:signpost', 'id': 'utility:signpost' }, + { 'iconName': 'utility:skip', 'id': 'utility:skip' }, + { 'iconName': 'utility:skip_back', 'id': 'utility:skip_back' }, + { 'iconName': 'utility:skip_forward', 'id': 'utility:skip_forward' }, + { 'iconName': 'utility:slider', 'id': 'utility:slider' }, + { 'iconName': 'utility:smiley_and_people', 'id': 'utility:smiley_and_people' }, + { 'iconName': 'utility:sms', 'id': 'utility:sms' }, + { 'iconName': 'utility:snippet', 'id': 'utility:snippet' }, + { 'iconName': 'utility:sobject', 'id': 'utility:sobject' }, + { 'iconName': 'utility:sobject_collection', 'id': 'utility:sobject_collection' }, + { 'iconName': 'utility:socialshare', 'id': 'utility:socialshare' }, + { 'iconName': 'utility:sort', 'id': 'utility:sort' }, + { 'iconName': 'utility:sort_policy', 'id': 'utility:sort_policy' }, + { 'iconName': 'utility:spinner', 'id': 'utility:spinner' }, + { 'iconName': 'utility:stage', 'id': 'utility:stage' }, + { 'iconName': 'utility:stage_collection', 'id': 'utility:stage_collection' }, + { 'iconName': 'utility:standard_objects', 'id': 'utility:standard_objects' }, + { 'iconName': 'utility:steps', 'id': 'utility:steps' }, + { 'iconName': 'utility:stop', 'id': 'utility:stop' }, + { 'iconName': 'utility:store', 'id': 'utility:store' }, + { 'iconName': 'utility:strategy', 'id': 'utility:strategy' }, + { 'iconName': 'utility:strikethrough', 'id': 'utility:strikethrough' }, + { 'iconName': 'utility:success', 'id': 'utility:success' }, + { 'iconName': 'utility:summary', 'id': 'utility:summary' }, + { 'iconName': 'utility:summarydetail', 'id': 'utility:summarydetail' }, + { 'iconName': 'utility:survey', 'id': 'utility:survey' }, + { 'iconName': 'utility:swarm_request', 'id': 'utility:swarm_request' }, + { 'iconName': 'utility:swarm_session', 'id': 'utility:swarm_session' }, + { 'iconName': 'utility:switch', 'id': 'utility:switch' }, + { 'iconName': 'utility:symbols', 'id': 'utility:symbols' }, + { 'iconName': 'utility:sync', 'id': 'utility:sync' }, + { 'iconName': 'utility:system_and_global_variable', 'id': 'utility:system_and_global_variable' }, + { 'iconName': 'utility:table', 'id': 'utility:table' }, + { 'iconName': 'utility:table_settings', 'id': 'utility:table_settings' }, + { 'iconName': 'utility:tablet_landscape', 'id': 'utility:tablet_landscape' }, + { 'iconName': 'utility:tablet_portrait', 'id': 'utility:tablet_portrait' }, + { 'iconName': 'utility:tabset', 'id': 'utility:tabset' }, + { 'iconName': 'utility:talent_development', 'id': 'utility:talent_development' }, + { 'iconName': 'utility:target', 'id': 'utility:target' }, + { 'iconName': 'utility:target_mode', 'id': 'utility:target_mode' }, + { 'iconName': 'utility:task', 'id': 'utility:task' }, + { 'iconName': 'utility:text', 'id': 'utility:text' }, + { 'iconName': 'utility:text_background_color', 'id': 'utility:text_background_color' }, + { 'iconName': 'utility:text_color', 'id': 'utility:text_color' }, + { 'iconName': 'utility:text_template', 'id': 'utility:text_template' }, + { 'iconName': 'utility:textarea', 'id': 'utility:textarea' }, + { 'iconName': 'utility:textbox', 'id': 'utility:textbox' }, + { 'iconName': 'utility:threedots', 'id': 'utility:threedots' }, + { 'iconName': 'utility:threedots_vertical', 'id': 'utility:threedots_vertical' }, + { 'iconName': 'utility:thunder', 'id': 'utility:thunder' }, + { 'iconName': 'utility:tile_card_list', 'id': 'utility:tile_card_list' }, + { 'iconName': 'utility:toggle', 'id': 'utility:toggle' }, + { 'iconName': 'utility:toggle_panel_bottom', 'id': 'utility:toggle_panel_bottom' }, + { 'iconName': 'utility:toggle_panel_left', 'id': 'utility:toggle_panel_left' }, + { 'iconName': 'utility:toggle_panel_right', 'id': 'utility:toggle_panel_right' }, + { 'iconName': 'utility:toggle_panel_top', 'id': 'utility:toggle_panel_top' }, + { 'iconName': 'utility:top_align', 'id': 'utility:top_align' }, + { 'iconName': 'utility:topic', 'id': 'utility:topic' }, + { 'iconName': 'utility:topic2', 'id': 'utility:topic2' }, + { 'iconName': 'utility:touch_action', 'id': 'utility:touch_action' }, + { 'iconName': 'utility:tracker', 'id': 'utility:tracker' }, + { 'iconName': 'utility:trail', 'id': 'utility:trail' }, + { 'iconName': 'utility:trailblazer_ext', 'id': 'utility:trailblazer_ext' }, + { 'iconName': 'utility:trailhead', 'id': 'utility:trailhead' }, + { 'iconName': 'utility:trailhead_alt', 'id': 'utility:trailhead_alt' }, + { 'iconName': 'utility:trailhead_ext', 'id': 'utility:trailhead_ext' }, + { 'iconName': 'utility:transparent', 'id': 'utility:transparent' }, + { 'iconName': 'utility:travel_and_places', 'id': 'utility:travel_and_places' }, + { 'iconName': 'utility:trending', 'id': 'utility:trending' }, + { 'iconName': 'utility:turn_off_notifications', 'id': 'utility:turn_off_notifications' }, + { 'iconName': 'utility:type', 'id': 'utility:type' }, + { 'iconName': 'utility:type_tool', 'id': 'utility:type_tool' }, + { 'iconName': 'utility:undelete', 'id': 'utility:undelete' }, + { 'iconName': 'utility:undeprecate', 'id': 'utility:undeprecate' }, + { 'iconName': 'utility:underline', 'id': 'utility:underline' }, + { 'iconName': 'utility:undo', 'id': 'utility:undo' }, + { 'iconName': 'utility:unlinked', 'id': 'utility:unlinked' }, + { 'iconName': 'utility:unlock', 'id': 'utility:unlock' }, + { 'iconName': 'utility:unmuted', 'id': 'utility:unmuted' }, + { 'iconName': 'utility:up', 'id': 'utility:up' }, + { 'iconName': 'utility:upload', 'id': 'utility:upload' }, + { 'iconName': 'utility:user', 'id': 'utility:user' }, + { 'iconName': 'utility:user_role', 'id': 'utility:user_role' }, + { 'iconName': 'utility:variable', 'id': 'utility:variable' }, + { 'iconName': 'utility:variation_attribute_setup', 'id': 'utility:variation_attribute_setup' }, + { 'iconName': 'utility:variation_products', 'id': 'utility:variation_products' }, + { 'iconName': 'utility:video', 'id': 'utility:video' }, + { 'iconName': 'utility:voicemail_drop', 'id': 'utility:voicemail_drop' }, + { 'iconName': 'utility:volume_high', 'id': 'utility:volume_high' }, + { 'iconName': 'utility:volume_low', 'id': 'utility:volume_low' }, + { 'iconName': 'utility:volume_off', 'id': 'utility:volume_off' }, + { 'iconName': 'utility:waits', 'id': 'utility:waits' }, + { 'iconName': 'utility:warning', 'id': 'utility:warning' }, + { 'iconName': 'utility:warranty_term', 'id': 'utility:warranty_term' }, + { 'iconName': 'utility:watchlist', 'id': 'utility:watchlist' }, + { 'iconName': 'utility:weeklyview', 'id': 'utility:weeklyview' }, + { 'iconName': 'utility:wellness', 'id': 'utility:wellness' }, + { 'iconName': 'utility:wifi', 'id': 'utility:wifi' }, + { 'iconName': 'utility:work_forecast', 'id': 'utility:work_forecast' }, + { 'iconName': 'utility:work_order_type', 'id': 'utility:work_order_type' }, + { 'iconName': 'utility:world', 'id': 'utility:world' }, + { 'iconName': 'utility:yubi_key', 'id': 'utility:yubi_key' }, + { 'iconName': 'utility:zoomin', 'id': 'utility:zoomin' }, + { 'iconName': 'utility:zoomout', 'id': 'utility:zoomout' } + +] + +const ICON_CATEGORIES = [ 'standard', 'custom', 'utility', 'action']; + +const MODES = { + ACCORDION: 'accordion', + TAB: 'tab', + COMBOBOX: 'combobox' +} +const CLASSES = { + OPEN: 'slds-is-open' +} + +const SEARCHBOX_ICONS = { + CLEAR: 'utility:clear', + SEARCH: 'utility:search' +} + +const DEFAULT_MAX_RESULTS = 100; + +const columns = [ + { label: 'Icon', fieldName: 'id', cellAttributes: { iconName: { fieldName: 'iconName' } } } +]; +export default class ObjectIconSelector extends LightningElement { + + @track actionIcons = ACTION_ICONS; + @track customIcons = CUSTOM_ICONS; + @track utilityIcons = UTILITY_ICONS; + @track standardIcons = STANDARD_ICONS; + + @track icons = []; + @track columns = columns; + + @api hideStandardIcons; + @api hideCustomIcons; + @api hideUtilityIcons; + @api hideActionIcons; + + @api + get iconCategories() { + return this._iconCategories; + } + set iconCategories(iconCategories) { + this._iconCategories = iconCategories; + for (let category of ICON_CATEGORIES) { + let hideProperty = 'hide' + category.charAt(0).toUpperCase() + category.slice(1) +'Icons'; + this[hideProperty] = !iconCategories.includes(category); + } + + } + + @api mode; + @api label = 'Pick an Icon'; + + // accordionMode is a legacy property added for backwards compatability and is not recommended for future use + @api + get accordionMode() { + return this._accordionMode; + } + set accordionMode(isAccMode) { + this._accordionMode = isAccMode; + this.mode = isAccMode ? MODES.ACCORDION : MODES.TAB; + } + _accordionMode; + + @api + get iconName() { + return this._iconName || null; + } + set iconName(iconName) { + this._iconName = iconName; + if (!this.rendered) { + return; + } + if (this.comboboxMode) { + this.setComboboxFormatting(); + } + const iconSelectedEvent = new CustomEvent('iconselection', { detail: iconName }); + this.dispatchEvent(iconSelectedEvent); + } + _iconName; + + activeSections = []; // 'S', 'U', 'C', 'A' + maxResults = DEFAULT_MAX_RESULTS + currentMaxResults = this.maxResults; + searchText; + noMatchesFoundString = 'No matches found'; + blockBlur; + rendered; + + + @api isAccordionLoading; // Reserved for future improvements + @api iconPickerButtonLabel; // reserved for future improvements + + @api + get tabStyle() { + let style; + if (this.firstTabHeight) { + style = `height: ${this.firstTabHeight}px`; + } + return style; + } + + @api + get tableStyle() { + return TABLE_STYLE; + } + + @api firstTabHeight; + + get tabMode() { return this.mode === MODES.TAB; } + get accordionMode() { return this.mode === MODES.ACCORDION; } + get comboboxMode() { return this.mode === MODES.COMBOBOX; } + get invalidMode() { return !this.tabMode && !this.accordionMode && !this.comboboxMode; } + + get displayedIcons() { + return this.filteredIcons.slice(0, this.currentMaxResults); + } + + get filteredIcons() { + if (!this.searchText) + return this.icons; + + return this.icons.filter(icon => { + return icon.iconName.toLowerCase().includes(this.searchText); + }); + } + + get resultsExceedMax() { + return this.filteredIcons.length > this.currentMaxResults; + } + + get loadMoreString() { + return 'Load more (' + this.currentMaxResults + ' of ' + this.filteredIcons.length + ' ' + (this.searchText ? 'matches' : 'options') + ' displayed)'; + } + + get searchboxIcon() { + return (this.searchText || this.iconName) ? SEARCHBOX_ICONS.CLEAR : SEARCHBOX_ICONS.SEARCH; + } + + get iconOptions() { + return this.icons.map(icon => { + return { + label: icon.iconName, + value: icon.iconName, + icon: icon.iconName + } + }); + } + + connectedCallback() { + if (!this.hideStandardIcons) this.icons.push(...this.standardIcons); + if (!this.hideCustomIcons) this.icons.push(...this.customIcons); + if (!this.hideUtilityIcons) this.icons.push(...this.utilityIcons); + // Action icons display weirdly in the combobox so I'm leaving them out for now + //if (!this.hideActionIcons) this.icons.push(...this.actionIcons); + } + + renderedCallback() { + if (this.rendered) return; + this.rendered = true; + + if (this.iconName) + this.iconName = this.iconName; + + } + + iconSelected(event) { + const selRow = event.detail.selectedRows[0]; + this.iconName = selRow.iconName; + // Moving the dispatch to iconName setter + // const iconSelectedEvent = new CustomEvent('iconselection', { detail: this.iconName }); + // this.dispatchEvent(iconSelectedEvent); + } + + + doSearch(searchText) { + this.searchText = searchText ? searchText.toLowerCase() : null; + this.showList(); + } + + showList() { + this.addClass('.slds-dropdown-trigger', CLASSES.OPEN); + this.focusSearchbox(); + } + + hideList() { + this.removeClass('.slds-dropdown-trigger', CLASSES.OPEN); + } + + loadMore() { + this.currentMaxResults += this.maxResults; + } + + focusSearchbox() { + this.template.querySelector('.comboboxInput').focus(); + } + + blurSearchbox() { + this.template.querySelector('.comboboxInput').blur(); + } + + clearSearchbox() { + this.iconName = null; + this.blockBlur = true; + this.doSearch(); + } + + setComboboxFormatting() { + if (this.iconName) { + this.addClass('.comboboxInput', 'slds-combobox__input-value'); + this.switchClass('.slds-combobox__form-element', 'slds-input-has-icon_right', 'slds-input-has-icon_left-right'); + this.addClass('.slds-combobox_container', 'slds-has-selection'); + this.template.querySelector('.comboboxInput').setAttribute('readonly', ''); + this.template.querySelector('.comboboxInput').value = this.iconName; + this.blurSearchbox(); + } else { + this.removeClass('.comboboxInput', 'slds-combobox__input-value'); + this.switchClass('.slds-combobox__form-element', 'slds-input-has-icon_left-right', 'slds-input-has-icon_right'); + this.removeClass('.slds-combobox_container', 'slds-has-selection'); + this.template.querySelector('.comboboxInput').removeAttribute('readonly'); + this.template.querySelector('.comboboxInput').value = null; + } + } + + + /* EVENT HANDLERS */ + handleIconSelect(event) { + let icon = event.currentTarget.dataset.icon; + this.iconName = icon; + } + + handleSearchFocus(event) { + if (!this.iconName) + this.doSearch(event.currentTarget.value); + } + + handleSearchChange(event) { + this.doSearch(event.currentTarget.value); + } + + handleSearchBlur() { + if (this.blockBlur) { + this.focusSearchbox(); + this.blockBlur = false; + } else { + this.currentMaxResults = this.maxResults; + this.hideList(); + } + } + + handleDropdownClick() { + this.blockBlur = true; + } + + handleSearchboxIconClick(event) { + if (event.currentTarget.iconName == SEARCHBOX_ICONS.CLEAR) { + this.clearSearchbox(); + } else { + this.doSearch(); + } + } + + handleComboboxChange(event) { + this.iconName = event.detail.value; + } + + /* UTITLITY FUNCTIONS */ + addClass(selector, className) { + let el = this.template.querySelector(selector); + if (el) + el.classList.add(className); + return !!el; + } + + removeClass(selector, className) { + let el = this.template.querySelector(selector); + if (el) + el.classList.remove(className); + return !!el; + } + + switchClass(selector, removeClass, addClass) { + this.removeClass(selector, removeClass); + this.addClass(selector, addClass); + } + + /* LEGACY PROPERTIES */ + @api showAccordion; + @api hideAccordion; +} diff --git a/force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml b/force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml new file mode 100644 index 0000000..d27a5dc --- /dev/null +++ b/force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml @@ -0,0 +1,29 @@ + + + 51.0 + true + Pick an Icon + Icon Picker + + lightning__FlowScreen + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js b/force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js new file mode 100644 index 0000000..22734a3 --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import IndicatorBuilder from 'c/indicatorBuilder'; + +describe('c-indicator-builder', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-indicator-builder', { + is: IndicatorBuilder + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css new file mode 100644 index 0000000..e0f8947 --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css @@ -0,0 +1,7 @@ +.slds-vertical-tabs, .slds-vertical-tabs * { + overflow: visible; +} + +.slds-vertical-tabs__content{ + overflow: visible; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html new file mode 100644 index 0000000..2af9a7c --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html @@ -0,0 +1,157 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js new file mode 100644 index 0000000..dae35cf --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js @@ -0,0 +1,201 @@ +import { LightningElement, api, track } from 'lwc'; + +export default class IndicatorBuilder extends LightningElement { + indSize = 'large'; + @api indShape = 'base'; + @api indText = ''; + @api indImage = ''; + indIcon = 'standard:marketing_actions'; + @api indHoverText = ''; + indBackgroundColor; + indForegroundColor; + + showMatch = {}; + iconSource = {} + showTextMatch = false; + showNumberMatch = false; + overrideColours = false; + + get activeVariantTabIndex() { + return this._activeVariantTabIndex; + } + set activeVariantTabIndex(value) { + this._activeVariantTabIndex = value; + this.itemVariants = this.itemVariants.map((variant, index) => { + variant.isActive = index == this.activeVariantTabIndex; + return variant; + }); + } + _activeVariantTabIndex = 0; + + @track itemVariants = []; + // { label: 'Default Indicator' } + // this.newIndicatorVariant('Default Indicator') + + + whenToDisplayOptions = [ + { label: 'Is not blank', value: 'notBlank' }, + { label: 'Is blank', value: 'isBlank' }, + { label: 'Contains text', value: 'containsText', showMatch: 'text' }, + { label: 'Equals text', value: 'equalsText', showMatch: 'text' }, + { label: 'Equals number', value: 'equalsNumber', showMatch: 'number' }, + { label: 'Is greater than', value: 'greaterThan', showMatch: 'number' }, + { label: 'Is less than', value: 'lessThan', showMatch: 'number' }, + { label: 'Is within range', value: 'inRange', showMatch: 'numericRange' }, + { label: 'Custom formula', value: 'customFormula' }, + { label: 'Custom exception', value: 'customException' }, + ]; + + iconSourceOptions = [ + { label: 'Lightning Icon', value: 'sldsIcon' }, + { label: 'Static Text', value: 'staticText' }, + { label: 'URL', value: 'url' }, + { label: 'Static Resource', value: 'staticResource' }, + ]; + + iconSizeOptions = [ + { label: 'x-small', value: 'x-small' }, + { label: 'small', value: 'small' }, + { label: 'medium', value: 'medium', default: true }, + { label: 'large', value: 'large' }, + ]; + + fieldLabelOptions = [ + { label: 'Hide field label', value: 'hide' }, + { label: 'Show standard label', value: 'standard' }, + { label: 'Show custom label', value: 'custom' }, + ] + + get showColourOption() { + return this.iconSource.sldsIcon || this.iconSource.staticText; + } + + get showColourSelectors() { + return this.showColourOption && this.overrideColours; + } + + connectedCallback() { + if (this.itemVariants.length === 0) { + console.log(`adding default variants`); + this.addNewVariant('When field has value', 'notBlank'); + this.addNewVariant('When field is blank', 'isBlank'); + this.activeVariantTabIndex = 0; + } + } + + handleWhenToDisplayChange(event) { + let value = event.detail.value; + let matchingOption = this.whenToDisplayOptions.find(option => option.value == value); + if (matchingOption) { + this.showMatch = { [matchingOption.showMatch]: true }; + } + } + + handleIconSourceChange(event) { + let value = event.detail.value; + let variantToUpdate = this.itemVariants[target.dataset.index]; + console.log(`value = ${value}`); + // this.iconSource = { [value]: true }; + variantToUpdate.iconSource = { [value]: true }; + } + + handleIconSelection(event) { + console.log(JSON.stringify(event.detail)); + this.indIcon = event.detail; + } + + handleStaticTextChange(event) { + this.indText = event.target.value; + } + + handleForegroundColourChange(event) { + this.indForegroundColor = event.target.value; + } + + handleBackgroundColourChange(event) { + this.indBackgroundColor = event.target.value; + } + + handleOverideColoursChange(event) { + this.overrideColours = event.target.checked; + } + + handleAddVariantClick() { + // this.itemVariants.push({ label: `Indicator Variant ${(this.itemVariants.length + 1)}`}); + // this.itemVariants.push(this.newIndicatorVariant(`Indicator Variant ${(this.itemVariants.length + 1)}`)); + this.addNewVariant(`Indicator Variant ${(this.itemVariants.length + 1)}`); + } + + handleTabAnchorClick(event) { + console.log(`in handleTabAnchorClick`); + this.activeVariantTabIndex = event.currentTarget.dataset.index; + console.log(`activeVariantTabIndex = ${this.activeVariantTabIndex}`); + } + + handleVariantPropertyChange(event) { + if (event.currentTarget.dataset.property) { + let target = event.currentTarget; + let tagName = target.tagName.toLowerCase(); + let value; + if (tagName === 'c-icon-selector') { + value = event.detail; + } else if (target.type === 'checkbox') { + value = target.checked; + } else if (tagName === 'lightning-combobox') { + value = event.detail.value; + } else { + value = target.value; + } + + console.log(`index is ${target.dataset.index}, value is ${value}, property name is ${target.dataset.property}`); + + let variantToUpdate = this.itemVariants[target.dataset.index]; + if (variantToUpdate) { + variantToUpdate[target.dataset.property] = value; + if (target.dataset.property === 'iconSource') { + variantToUpdate.sourceValue = null; + } + this.itemVariants = [...this.itemVariants]; + console.log(`updated variant value = ${JSON.stringify(variantToUpdate)}`); + } + } + } + + addNewVariant(label, whenToDisplay) { + this.itemVariants.push(this.newIndicatorVariant(label, whenToDisplay)); + this.activeVariantTabIndex = this.itemVariants.length - 1; + } + + newIndicatorVariant(label, whenToDisplay, isActive = true, iconSource = 'sldsIcon') { + let whenToDisplayOptions = this.whenToDisplayOptions; + + let newVariant = { + label, + whenToDisplay, + isActive, + iconSource, + hoverText: '', + get iconSourceIs() { + return { [this.iconSource]: true } + }, + get filterTypeIs() { + let matchingOption = whenToDisplayOptions.find(option => option.value == this.whenToDisplay); + return matchingOption ? { [matchingOption.showMatch]: true } : {}; + }, + get tabAnchorClass() { + return 'slds-vertical-tabs__nav-item' + (this.isActive ? ' slds-is-active' : ''); + }, + get tabPaneClass() { + return 'slds-vertical-tabs__content ' + (this.isActive ? 'slds-show' : 'slds-hide'); + }, + get showColourOption() { + return this.iconSourceIs.sldsIcon; + }, + get showColourSelectors() { + return this.iconSourceIs.staticText || (this.showColourOption && this.overrideColours); + } + } + console.log(`newVariant = ${JSON.stringify(newVariant)}`); + return newVariant; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml new file mode 100644 index 0000000..f6b2657 --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml @@ -0,0 +1,8 @@ + + + 58.0 + true + + lightning__Tab + + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js index 2d23e31..4872229 100644 --- a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js +++ b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js @@ -2,34 +2,84 @@ import { LightningElement, api } from 'lwc'; export default class IndicatorListItem extends LightningElement { @api indSize = 'large'; - @api indShape = 'base'; - @api indText = ''; - @api indImage = ''; - @api indIcon = 'standard:marketing_actions'; - @api indHoverText = ''; - @api indBackgroundColor; - @api indForegroundColor; + // @api indShape = 'base'; + // @api indText = ''; + // @api indImage = ''; + // @api indIcon = 'standard:all' ; + // @api indHoverText = ''; - get indClass() { - let classValue = ''; - if(this.indBackgroundColor || this.indForegroundColor){ - classValue = 'indicatorIcon '; + @api iconSource; + @api sourceValue; + + @api get indBackgroundColor() { + return this._indBackgroundColor; + }; + set indBackgroundColor(value) { + this._indBackgroundColor = value; + if (this.iconElement) { + this.iconElement.style.setProperty('--backgroundColor', this.indBackgroundColor); + console.log(`setting background colour to ${this.indBackgroundColor}`); + } else { + console.log(`iconElement not found`); + } + } + _indBackgroundColor; + @api get indForegroundColor() { + return this._indForegroundColor; + }; + set indForegroundColor(value) { + this._indForegroundColor = value; + if (this.iconElement) { + this.iconElement.style.setProperty('--foregroundColor', this.indForegroundColor); + console.log(`setting foreground colour to ${this.indForegroundColor}`); + } else { + console.log(`iconElement not found`); } + } + _indForegroundColor; + + get indClass() { + let classValue = ['indicatorIcon']; + // if(this.indBackgroundColor || this.indForegroundColor){ + // classValue = 'indicatorIcon '; + // } if(this.indSize == 'large'){ - classValue += 'slds-var-m-right_small slds-var-m-vertical_medium'; + classValue.push('slds-var-m-right_small','slds-var-m-vertical_medium'); } else { - classValue += 'slds-var-m-right_x-small slds-var-m-vertical_small'; + classValue.push('slds-var-m-right_x-small', 'slds-var-m-vertical_small'); } if(this.indIcon == 'none'){ - classValue += 'slds-var-m-right_xxx-small slds-var-m-vertical_small slds-avatar__initials_inverse' + classValue.push('slds-var-m-right_xxx-small', 'slds-var-m-vertical_small', 'slds-avatar__initials_inverse'); + } + return classValue.join(' '); + } + + get iconElement() { + return this.template.querySelector(".indicatorIcon"); + } + + get indText() { + return (this.iconSource === 'staticText') ? (this.sourceValue || ' ') : ''; + } + + get indUrl() { + return (this.iconSource === 'url' || this.iconSource === 'staticResource') ? this.sourceValue : ''; + } + + get indIcon() { + if (this.iconSource === 'sldsIcon') { + return this.sourceValue; + } else if (this.iconSource === 'staticText') { + return 'standard:empty'; + } else { + return ''; } - - return classValue; } + /* No longer need to set CSS on renderedCallback because it's controlled in setters for colors renderedCallback() { this.initCSSVariables(); } @@ -44,4 +94,5 @@ export default class IndicatorListItem extends LightningElement { } } + */ } \ No newline at end of file From 5321bfbb6e0f8ecc259428c0915c4893e60285fa Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Tue, 31 Oct 2023 15:36:05 -0500 Subject: [PATCH 02/23] Added CSS line to change utility icon foreground --- .../main/default/lwc/indicatorBundleItem/indicatorBundleItem.css | 1 + 1 file changed, 1 insertion(+) diff --git a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css index d6ee94b..376147c 100644 --- a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css +++ b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css @@ -3,6 +3,7 @@ } .indicatorIcon { + --sds-c-icon-color-foreground-default: var(--foregroundColor); --sds-c-icon-color-foreground: var(--foregroundColor); --sds-c-icon-color-background: var(--backgroundColor); --slds-c-avatar-text-color: var(--foregroundColor); From f35ab43411a9bcde0fa1123ee3946a51e4e462b1 Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Tue, 31 Oct 2023 15:52:35 -0500 Subject: [PATCH 03/23] Adding objectFieldSelector --- .../fsc_objectFieldSelector.html | 28 +++ .../fsc_objectFieldSelector.js | 189 ++++++++++++++++++ .../fsc_objectFieldSelector.js-meta.xml | 32 +++ .../indicatorBundleItem.js | 2 +- 4 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html new file mode 100644 index 0000000..54c3a73 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js new file mode 100644 index 0000000..2b3cf2d --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js @@ -0,0 +1,189 @@ +import { LightningElement, api, track } from 'lwc'; +import { FlowAttributeChangeEvent } from 'lightning/flowSupport'; + +import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_comboboxUtils'; + +export default class Fsc_objectFieldSelector extends LightningElement { + availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); + + @api name; + @api masterLabel; + @api objectLabel = 'Select Object'; + @api fieldLabel = 'Select Field'; + @api valueDelimiter = ','; + + @api disableObjectPicklist = false; + @api hideObjectPicklist = false; + @api hideFieldPicklist = false; + @api objectAllowMultiselect = false; + @api fieldAllowMultiselect = false; + @api required = false; + + @api availableObjectSelection = this.availableObjectOptions.default?.value; + @api availableObjects; + @api availableFieldTypes; + @api availableReferenceTypes; + @api lockDefaultObject; + @api defaultToNameField; + @api layout = LAYOUT_OPTIONS.VERTICAL.value; + + @api + get builderContext() { + return this._builderContext; + } + set builderContext(value) { + console.log('setting builderContext'); + console.log(JSON.stringify(value)); + this._builderContext = value; + } + _builderContext; + + @api + get objectValues() { + return this._objectValues || []; + } + set objectValues(values) { + this._objectValues = setValuesFromMultipleInput(values); + } + @track _objectValues = []; + + @api + get objectValue() { + return this.objectValues.join(this.valueDelimiter); + } + set objectValue(value) { + console.log('in set objectValue'); + console.log(value); + this.objectValues = setValuesFromSingularInput(value, this.valueDelimiter, this.objectAllowMultiselect); + } + + @api + get fieldValues() { + return this._fieldValues || []; + } + set fieldValues(values) { + this._fieldValues = setValuesFromMultipleInput(values); + } + @track _fieldValues = []; + + @api + get fieldValue() { + return this.fieldValues.join(this.valueDelimiter); + } + set fieldValue(value) { + this.fieldValues = setValuesFromSingularInput(value, this.valueDelimiter, this.fieldAllowMultiselect); + } + + + @api + get displayType() { + return this._displayType; + } + set displayType(value) { + this._displayType = value; + if (this.displayType === DISPLAY_TYPE_OPTIONS.FIELD.value) { + this.hideObjectPicklist = true; + } + if (this.displayType === DISPLAY_TYPE_OPTIONS.OBJECT.value) { + this.hideFieldPicklist = true; + } + } + + @api + reportValidity() { + let isValid = true; + if (this.objectSelector) { + isValid = this.objectSelector.reportValidity() && isValid; + } + if (this.fieldSelector) { + isValid = this.fieldSelector.reportValidity() && isValid; + } + return isValid; + } + + @api + validate() { + let errorMessages = [] + const validateComponents = [this.objectSelector, this.fieldSelector]; + validateComponents.forEach(cmp => { + if (cmp?.validate().errorMessage) { + errorMessages.push(cmp.validate().errorMessage) + } + }) + // if (this.objectSelector && this.objectSelector.validate().errorMessage) { + // errorMessages.push(this.objectSelector.validate().errorMessage) + // } + // if (this.fieldSelector && this.fieldSelector.validate().errorMessage) { + // errorMessages.push(this.fieldSelector.validate().errorMessage) + // } + console.log('in ofsValidate, errorMessages = ' + errorMessages); + if (errorMessages.length) { + return { + isValid: false, + errorMessage: errorMessages.join(' ') + }; + } else { + return { isValid: true }; + } + } + + get computedColClass() { + let classString = 'slds-col'; + if (this.displayType === DISPLAY_TYPE_OPTIONS.BOTH.value && this.layout === LAYOUT_OPTIONS.HORIZONTAL.value) { + classString += ' slds-size_1-of-2'; + } else { + classString += ' slds-size_1-of-1'; + } + return classString; + } + + get objectSelector() { + return this.template.querySelector('c-fsc_object-selector'); + } + + get fieldSelector() { + return this.template.querySelector('c-fsc_field-selector2'); + } + + handleObjectChange(event) { + this.objectValue = event.detail.value; + const attributeChangeEvent = new FlowAttributeChangeEvent( + 'objectValue', + this.objectValue + ); + this.dispatchEvent(attributeChangeEvent); + this.dispatchValues(); + } + + handleFieldChange(event) { + this.fieldValue = event.detail.value; + const attributeChangeEvent = new FlowAttributeChangeEvent( + 'fieldValue', + this.fieldValue + ); + this.dispatchEvent(attributeChangeEvent); + this.dispatchValues(); + } + + dispatchValues() { + this.dispatchEvent(new CustomEvent('change', { + detail: { + objectValue: this.objectValue, + objectValues: this.objectValues, + fieldValue: this.fieldValue, + fieldValues: this.fieldValues + } + })); + } + + + connectedCallback() { + // console.log('displayType = ' + this.displayType); + // console.log('objectValue = ' + this.objectValue); + // console.log('availableFieldTypes = ' + this.availableFieldTypes); + // console.log('availableReferenceTypes = ' + this.availableReferenceTypes); + // console.log('hideObjectPicklist = ' + this.hideObjectPicklist); + // console.log('hideFieldPicklist = ' + this.hideFieldPicklist); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml new file mode 100644 index 0000000..498f554 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml @@ -0,0 +1,32 @@ + + + 54.0 + true + Object and Field Selector + + lightning__FlowScreen + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js index 4872229..7270149 100644 --- a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js +++ b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js @@ -6,7 +6,7 @@ export default class IndicatorListItem extends LightningElement { // @api indText = ''; // @api indImage = ''; // @api indIcon = 'standard:all' ; - // @api indHoverText = ''; + @api indHoverText = ''; @api iconSource; @api sourceValue; From 0ea9561de8213fd18f63bd6b58ac3c5597d6b074 Mon Sep 17 00:00:00 2001 From: tschug Date: Tue, 6 Feb 2024 18:59:12 -0500 Subject: [PATCH 04/23] Updated Flexipages to remove news tab/twitter component --- .../Account_Record_Page_Indicators.flexipage | 25 ------------------- .../Contact_Record_Page_Indicators.flexipage | 25 ------------------- 2 files changed, 50 deletions(-) diff --git a/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Account_Record_Page_Indicators.flexipage b/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Account_Record_Page_Indicators.flexipage index dfb7f62..3d88e33 100644 --- a/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Account_Record_Page_Indicators.flexipage +++ b/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Account_Record_Page_Indicators.flexipage @@ -81,17 +81,6 @@ detailTabContent Facet - - - - runtime_sales_social:socialPanel - runtime_sales_social_socialPanel - - - Replace - newsTabContent - Facet - @@ -125,20 +114,6 @@ detailTab - - - - body - newsTabContent - - - title - Standard.Tab.news - - flexipage:tab - newsTab - - Replace maintabs Facet diff --git a/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Contact_Record_Page_Indicators.flexipage b/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Contact_Record_Page_Indicators.flexipage index 7b99015..f6ded4f 100644 --- a/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Contact_Record_Page_Indicators.flexipage +++ b/unpackaged/config/sample_AccountContact_FlexiPages/flexipages/Contact_Record_Page_Indicators.flexipage @@ -75,17 +75,6 @@ detailTabContent Facet - - - - runtime_sales_social:socialPanel - runtime_sales_social_socialPanel - - - Replace - newsTabContent - Facet - @@ -119,20 +108,6 @@ detailTab - - - - body - newsTabContent - - - title - Standard.Tab.news - - flexipage:tab - newsTab - - Replace maintabs Facet From a829e85bdb4b0a2f8a5544561389a82f5ffffa25 Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Tue, 31 Oct 2023 15:23:56 -0500 Subject: [PATCH 05/23] First build of indicator builder --- .../classes/ObjectFieldSelectorController.cls | 114 ++ ...ObjectFieldSelectorController.cls-meta.xml | 5 + .../ObjectFieldSelectorControllerTest.cls | 18 + ...ctFieldSelectorControllerTest.cls-meta.xml | 5 + .../default/lwc/fsc_combobox/fsc_combobox.css | 3 + .../lwc/fsc_combobox/fsc_combobox.html | 182 +++ .../default/lwc/fsc_combobox/fsc_combobox.js | 586 +++++++ .../lwc/fsc_combobox/fsc_combobox.js-meta.xml | 14 + .../fsc_comboboxUtils/fsc_comboboxUtils.js | 33 + .../fsc_comboboxUtils.js-meta.xml | 5 + .../fsc_fieldSelector2.html | 25 + .../fsc_fieldSelector2/fsc_fieldSelector2.js | 235 +++ .../fsc_fieldSelector2.js-meta.xml | 5 + .../fsc_objectFieldSelectorUtils.js | 58 + .../fsc_objectFieldSelectorUtils.js-meta.xml | 5 + .../fsc_objectSelector.html | 24 + .../fsc_objectSelector/fsc_objectSelector.js | 157 ++ .../fsc_objectSelector.js-meta.xml | 15 + .../lwc/iconSelector/iconSelector.html | 45 + .../default/lwc/iconSelector/iconSelector.js | 1406 +++++++++++++++++ .../lwc/iconSelector/iconSelector.js-meta.xml | 29 + .../__tests__/indicatorBuilder.test.js | 25 + .../lwc/indicatorBuilder/indicatorBuilder.css | 7 + .../indicatorBuilder/indicatorBuilder.html | 157 ++ .../lwc/indicatorBuilder/indicatorBuilder.js | 201 +++ .../indicatorBuilder.js-meta.xml | 8 + .../indicatorBundleItem.js | 83 +- 27 files changed, 3434 insertions(+), 16 deletions(-) create mode 100644 force-app/main/default/classes/ObjectFieldSelectorController.cls create mode 100644 force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml create mode 100644 force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls create mode 100644 force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.css create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.html create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.js create mode 100644 force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js create mode 100644 force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html create mode 100644 force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js create mode 100644 force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml create mode 100644 force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html create mode 100644 force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js create mode 100644 force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml create mode 100644 force-app/main/default/lwc/iconSelector/iconSelector.html create mode 100644 force-app/main/default/lwc/iconSelector/iconSelector.js create mode 100644 force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml create mode 100644 force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js create mode 100644 force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml diff --git a/force-app/main/default/classes/ObjectFieldSelectorController.cls b/force-app/main/default/classes/ObjectFieldSelectorController.cls new file mode 100644 index 0000000..22b6aab --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorController.cls @@ -0,0 +1,114 @@ +public with sharing class ObjectFieldSelectorController { + + public static final String STANDARD = 'standard'; + public static final String SPECIFIC = 'specific'; + public static final String CUSTOM = 'custom'; + public static final String BOTH = 'both'; + public static final String ANCILLARY = 'ancillary'; + public static final String ALL = 'all'; + + @AuraEnabled + public static GetObjectsResult getObjects(String selectionType, List availableObjects) { + if (String.isBlank(selectionType)) + selectionType = BOTH; + selectionType = selectionType.toLowerCase(); + GetObjectsResult result = new GetObjectsResult(); + result.objects = new List(); + List describeResults = new List(); + if (selectionType == ALL) { + Map objMap = Schema.getGlobalDescribe(); + for (Schema.SObjectType objType : objMap.values()) { + describeResults.add(objType.getDescribe()); + } + } else if (selectionType == SPECIFIC) { + describeResults = Schema.describeSObjects(availableObjects); + } else { + List objectNames = new List(); + List entityDefs = new List(); + if (selectionType == STANDARD || selectionType == BOTH) { + entityDefs.addAll([SELECT KeyPrefix, QualifiedApiName, DeveloperName FROM EntityDefinition WHERE (NOT QualifiedApiName LIKE '%__c') AND (NOT QualifiedApiName LIKE '%Feed') AND (NOT QualifiedApiName LIKE '%Tag') AND (NOT QualifiedApiName LIKE '%Share') AND (NOT QualifiedApiName LIKE '%ChangeEvent') AND (NOT QualifiedApiName LIKE '%History')]); + } + if (selectionType == CUSTOM || selectionType == BOTH) { + entityDefs.addAll([SELECT QualifiedApiName FROM EntityDefinition WHERE QualifiedApiName LIKE '%__c']); + } + if (selectionType == ANCILLARY) { + entityDefs.addAll([SELECT QualifiedApiName, DeveloperName FROM EntityDefinition WHERE QualifiedApiName LIKE '%Feed' OR QualifiedApiName LIKE '%Tag' OR QualifiedApiName LIKE '%Share' OR QualifiedApiName LIKE '%ChangeEvent' OR QualifiedApiName LIKE '%History']); + } + for (EntityDefinition def : entityDefs) { + // The standard list of EntityDefinitions may still return some odd types like metadata, so we filter out any object with double underscores + if (selectionType != STANDARD || !def.QualifiedApiName.contains('__')) { + objectNames.add(def.QualifiedApiName); + } + } + describeResults = Schema.describeSObjects(objectNames); + } + for (Schema.DescribeSObjectResult res : describeResults) { + result.objects.add(new ObjectResult(res.getLabel(), res.getName())); + } + return result; + } + + @AuraEnabled(cacheable=true) + public static GetObjectFieldsResult getObjectFields(String objectName) { + GetObjectFieldsResult result = new GetObjectFieldsResult(); + result.fields = new List(); + try { + Map tokenMap = ((SObject)Type.forName('Schema', objectName).newInstance()).getSObjectType().getDescribe().fields.getMap(); + for (Schema.SObjectField objField : tokenMap.values()) { + FieldResult newField = new FieldResult(objField.getDescribe()); + System.debug(newField); + result.fields.add(newField); + } + } catch (Exception e) { + result.errorMessage = e.getMessage(); + return result; + } + System.debug('about to return result, with '+ result.fields.size() +' fields'); + return result; + } + + public class GetObjectsResult { + @AuraEnabled public List objects; + } + + public class ObjectResult { + @AuraEnabled public String label; + @AuraEnabled public String value; + + public ObjectResult(String label, String value) { + this.label = label; + this.value = value; + } + } + + public class GetObjectFieldsResult { + @AuraEnabled public String errorMessage; + @AuraEnabled public List fields; + } + + public class FieldResult { + @AuraEnabled public String apiName; + @AuraEnabled public String label; + @AuraEnabled public String dataType; + @AuraEnabled public List referenceToInfos; + + public FieldResult(Schema.DescribeFieldResult fieldResult) { + this.apiName = fieldResult.getName(); + this.label = fieldResult.getLabel(); + this.dataType = fieldResult.getType().name(); + List refToInfos = new List(); + for (Schema.sObjectType objType : fieldResult.getReferenceTo()) { + refToInfos.add(new ReferenceToInfo(objType.getDescribe().getName())); + } + this.referenceToInfos = refToInfos; + } + } + + public class ReferenceToInfo { + @AuraEnabled public String apiName; + + public ReferenceToInfo(String apiName) { + this.apiName = apiName; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml b/force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml new file mode 100644 index 0000000..40d6793 --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls new file mode 100644 index 0000000..76fcfd9 --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls @@ -0,0 +1,18 @@ +@isTest +public class ObjectFieldSelectorControllerTest { + + @isTest + public static void testOFSController() { + ObjectFieldSelectorController.GetObjectsResult result1 = ObjectFieldSelectorController.getObjects('all', new List()); + ObjectFieldSelectorController.GetObjectsResult result2 = ObjectFieldSelectorController.getObjects('both', new List()); + ObjectFieldSelectorController.GetObjectsResult result3 = ObjectFieldSelectorController.getObjects('specific', new List{'Account', 'Opportunity'}); + System.assertEquals(result3.objects.size(), 2); + System.assert(result3.objects.size() < result2.objects.size()); + System.assert(result2.objects.size() < result1.objects.size()); + + ObjectFieldSelectorController.GetObjectFieldsResult result4 = ObjectFieldSelectorController.getObjectFields('Account'); + ObjectFieldSelectorController.GetObjectFieldsResult result5 = ObjectFieldSelectorController.getObjectFields('NotARealObject'); + System.assert(String.isBlank(result4.errorMessage)); + System.assert(!String.isBlank(result5.errorMessage)); + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml new file mode 100644 index 0000000..40d6793 --- /dev/null +++ b/force-app/main/default/classes/ObjectFieldSelectorControllerTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.css b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.css new file mode 100644 index 0000000..70ed2a5 --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.css @@ -0,0 +1,3 @@ +.disabledCursor, .disabledCursor ~ .slds-button { + cursor: not-allowed; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.html b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.html new file mode 100644 index 0000000..385c1db --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.html @@ -0,0 +1,182 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js new file mode 100644 index 0000000..dd13296 --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js @@ -0,0 +1,586 @@ +// Style from: https://www.lightningdesignsystem.com/components/combobox +import { LightningElement, api, track } from 'lwc'; +import { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } from 'c/fsc_comboboxUtils'; + +const VARIANTS = { + BASE: 'base', + STANDARD: 'standard', + LABEL_HIDDEN: 'label-hidden' +} + +const LOAD_COUNT = 50; + +export default class OptionSelector extends LightningElement { + /* PUBLIC PROPERTIES */ + @api publicStyle; + @api publicClass; + @api label; + @api name; + @api customSearchHandler; // Custom function to be executed by handleSearchChange, passed in from a parent component. + @api messageWhenValueMissing = 'Please select at least one option.'; + @api iconSize = 'x-small'; + @api placeholder = 'Select an option'; + @api noMatchString = 'No matches found'; + @api valueDelimiter = ','; + @api rightIcon = 'utility:down'; // Icon to be displayed on the right side of the search input + @api groupingTextClass = 'slds-listbox__option-header'; + @api fieldLevelHelp; + @api errorMessage; + @api variant; + @api required = false; + @api disabled = false; + @api isLoading = false; + @api allowMultiselect = false; + // @api variant = VARIANTS.STANDARD; // RESERVED FOR FUTURE USE If set to 'base', when allowMultiselect is false, when the combobox has a value set it will appear like a base combobox rather than as an autocomplete + @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). + @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. + @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + @api filterActions = false; // If true, action items will be filtered along with selection items. By default, action items are always visible + @api showSelectedCount = false; // If true, when allowMultiselect is true, the component label will show the number of selected values in parentheses + @api hideSelectedValues = false; // Reserved for future use + + @api builderContext; + + /* PRIVATE PROPERTIES */ + @track _options = []; + @track _values = []; + @track _groupings = []; + @track onRender = {}; // Used to manage actions on render + @track onLoad = []; + pillsNotFittingCount = 0; + numOptionsDisplayed = LOAD_COUNT; + pillContainerIsExpanded = false; + pillsGoMultiLine = false; + pillTops = []; + debounceTimer; + showList; + _highlightedOptionIndex; + + /* PUBLIC GETTERS & SETTERS */ + @api + get debounceDelay() { + return this._debounceDelay; + } + set debounceDelay(delay) { + this._debounceDelay = parseInt(delay) || 0; + } + _debounceDelay = 0; + + @api + get options() { + return this._options || []; + } + set options(options) { + let groupings = []; + if (Array.isArray(options)) { + this._options = options.map((option, index) => { + if (option.grouping && !groupings.includes(option.grouping)) { + groupings.push(option.grouping); + } + return this.getComboboxOption(option, index); + }); + + if (groupings.length) { + let newIndex = 0; + let groupedOptions = []; + this._options.filter(option => !option.grouping).forEach(groupingOption => { + groupingOption.index = newIndex; + groupedOptions.push(groupingOption); + newIndex++; + }); + + groupings.forEach(grouping => { + groupedOptions.push({ label: grouping, isGrouping: true, index: newIndex }); + newIndex++; + this._options.filter(option => option.grouping == grouping).forEach(groupingOption => { + groupingOption.index = newIndex; + groupedOptions.push(groupingOption); + newIndex++; + }); + }) + this._options = groupedOptions; + } + this.filterOptions(); + } else { + this._options = []; + } + } + + @api + get values() { + return this._values || []; + } + set values(values) { + this._values = setValuesFromMultipleInput(values); + // if (!values) { + // this._values = []; + // } else { + // this._values = Array.isArray(values) ? [...values] : [values]; + // } + } + + @api + get value() { + return this.values.join(this.valueDelimiter); + } + set value(value) { + this.values = setValuesFromSingularInput(value, this.valueDelimiter, this.allowMultiselect); + // if (!value) { + // this.values = []; + // } else { + // this.values = this.allowMultiselect ? value.split(this.valueDelimiter).map(val => val.trim()) : [value]; + // } + } + + @api + get groupings() { + return this._groupings || []; + } + set groupings(value) { + this._groupings = value.map(grouping => { + return { + value: grouping.value, + label: grouping.label + } + }) + let groupedOptions = []; + value.forEach(grouping => { + let currentGroupingOptions = grouping.options.map(option => { + return { + ...option, + grouping: grouping.label + } + }); + groupedOptions.push(...currentGroupingOptions); + }); + this.options = groupedOptions; + } + + @api + get selectedOptions() { + let selectedOptions = []; + this.values.forEach(value => { + const option = this.options.find(option => option.value === value); + if (option) { + selectedOptions.push(option); + } + }); + return selectedOptions; + } + + get selectedOption() { + return this.selectedOptions.length ? this.selectedOptions[0] : null; + } + + /* PUBLIC FUNCTIONS */ + @api + reportValidity() { + if (!this.required || this.selectedOptions.length) { + this.setCustomValidity(); + } else { + this.setCustomValidity(this.messageWhenValueMissing); + } + return !this.errorMessage; + } + + @api + validate() { + if (this.reportValidity()) { + return { isValid: true }; + } else { + return { + isValid: false, + errorMessage: this.errorMessage + } + } + } + + @api + setCustomValidity(errorMessage) { + this.errorMessage = errorMessage; + } + + /* LIFECYCLE HOOKS */ + connectedCallback() { + window.addEventListener("resize", () => { this.resizePillContainer() }); + + } + + renderedCallback() { + if (this.onRender.inputFocus) { + this.onRender.inputFocus = false; + this.inputElement?.focus(); + // this.inputElement ? this.inputElement.focus() : this.template.querySelector('.slds-combobox__input').focus(); + } + if (this.onRender.highlightOption) { + this.onRender.highlightOption = false; + const highlightedOption = this.template.querySelector('[data-has-focus="true"]'); + this.scrollIntoViewIfNeeded(highlightedOption, this.listboxElement); + } + + // Check to see if the arrangement of pills has changed since last render + let newPillTops = [...this.pillElements].map(pill => pill.offsetTop); + if (!(this.pillTops.length == newPillTops.length && this.pillTops.every((val, index) => val === newPillTops[index]))) { + this.pillTops = newPillTops; + this.resizePillContainer(); + } + } + + /* PRIVATE GETTERS AND SETTERS */ + get highlightedOptionIndex() { + return this._highlightedOptionIndex; + } + set highlightedOptionIndex(value) { + this._highlightedOptionIndex = value; + this.options.forEach(option => option.hasFocus = option.index === this.highlightedOptionIndex); // Update the hasFocus property for all options + } + + /* DOM ELEMENT GETTERS */ + get inputElement() { + return this.template.querySelector('input'); + } + + get listboxElement() { + return this.template.querySelector('[role="listbox"]'); + } + + get pillElements() { + return this.template.querySelectorAll('lightning-pill'); + } + + /* COMPUTED LOGIC VALUES */ + get displayedOptions() { + return this.options.slice(0, this.numOptionsDisplayed); + } + + get isInputDisabled() { + return this.disabled || this.isLoading; + } + + get noMatchFound() { + return this.options.every(option => option.hidden || option.isAction); + } + + get showSelectedValue() { + return !this.allowMultiselect && this.selectedOption; + } + + get showPills() { + return this.allowMultiselect && !this.hidePills && this.values.length; + } + + get computedLabel() { + return this.label + ((this.allowMultiselect && this.showSelectedCount) ? ' (' + this.values.length + ')' : ''); + } + + get isBaseVariant() { + return this.variant === VARIANTS.BASE; + } + + get showLabel() { + return this.variant !== VARIANTS.LABEL_HIDDEN; + } + + /* COMPUTED CSS CLASS STRINGS */ + get computedSelectedValueClass() { + return 'slds-combobox__form-element slds-input-has-icon' + (this.selectedOption?.icon ? ' slds-input-has-icon_left-right' : ' slds-input-has-icon_right'); + } + + get computedFormElementClass() { + return 'slds-form-element' + (this.errorMessage ? ' slds-has-error' : ''); + } + + get computedComboboxContainerClass() { + return 'slds-combobox_container' + ((this.value && !this.isBaseVariant) ? ' slds-has-selection' : ''); + } + + get computedComboboxClass() { + return 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click' + (this.showList ? ' slds-is-open' : ''); + } + + get computedListboxSelectionGroupClass() { + return 'slds-listbox_selection-group' + (this.pillContainerIsExpanded ? ' slds-is-expanded' : ''); + } + + get computedFauxInputClass() { + return 'slds-input_faux slds-combobox__input slds-combobox__input-value' + (this.disabled ? ' slds-theme_shade disabledCursor' : ''); + } + + /* ACTION FUNCTIONS */ + openList() { + this.showList = true; + this.onRender.inputFocus = true; + } + + closeList() { + this.showList = false; + this.highlightedOptionIndex = undefined; + this.numOptionsDisplayed = LOAD_COUNT; + if (this.listboxElement) + this.listboxElement.scrollTop = 0; + } + + resetSearch() { + this.inputElement.value = ''; + this.filterOptions(); + } + + filterOptions() { + let searchText = (this.inputElement?.value || '').toLowerCase(); + // console.log('in filterOptions', searchText); + let numDisplayedCount = 0; + for (let option of this.options) { + if (numDisplayedCount > this.numOptionsDisplayed) { + option.hidden = true; + } else if (searchText && option.isGrouping) { + option.hidden = true; + } else if (this.values.includes(option.value)) { + // If the option has already been selected, hide it from the list of available options + option.hidden = true; + } + else { + // If the option's label matches the search text, display it. Also optionally check the option's sublabel and value. + if (option.label.toLowerCase().includes(searchText) + || (this.includeValueInFilter && option.value.toLowerCase().includes(searchText)) + || (!this.excludeSublabelInFilter && option.sublabel && option.sublabel.toLowerCase().includes(searchText))) { + option.hidden = false; + if (option.grouping) { + this.options.find(grouping => grouping.isGrouping && grouping.label == option.grouping).hidden = false; + } + } else { + option.hidden = true; + } + } + + if (!option.hidden) { + numDisplayedCount++; + } + } + } + + selectOption(index) { + let selectedOption = this.options[index]; + // console.log('selecting '+ JSON.stringify(selectedOption)); + // console.log('value before adding: '+ this.value); + // console.log('values before adding: '+ JSON.stringify(this.values) +', length: '+ this.values.length); + if (!selectedOption) { + return; + } + if (selectedOption.isAction) { + this.dispatchEvent(new CustomEvent('customaction', { detail: selectedOption.value })); + } else { + this.values.push(selectedOption.value); + this.values = this.values; + // this.values = [...this.values, selectedOption.value]; // using spread instead of values.push to trigger the setter + this.resetSearch(); + this.dispatchOptions(); + this.onRender.inputFocus = true; + } + } + + unselectOption(index) { + this.values = [...this.values.slice(0, index), ...this.values.slice(Number(index) + 1)]; + this.dispatchOptions(); + } + + dispatchOptions() { + let detail = { + value: this.value, + values: this.values, + //selectedOptions: this.selectedOptions + } + this.dispatchEvent(new CustomEvent('change', { detail })); + } + + highlightNextOption(startIndex) { + if (!startIndex || startIndex >= this.options.length) { + startIndex = 0; + } + if (this.options[startIndex].hidden || this.options[startIndex].isGrouping) { + this.highlightNextOption(Number(startIndex) + 1); + } else { + this.highlightOption(startIndex); + } + } + + highlightPreviousOption(startIndex) { + if ((startIndex !== 0 && !startIndex) || startIndex < 0) { + startIndex = this.options.length - 1; + } + if (this.options[startIndex].hidden || this.options[startIndex].isGrouping) { + this.highlightPreviousOption(Number(startIndex) - 1); + } else { + this.highlightOption(startIndex); + } + } + + highlightOption(index) { + this.highlightedOptionIndex = index; + this.onRender.highlightOption = true; + } + + resizePillContainer() { + let notFittingCount = 0; + this.pillElements.forEach((pill) => { + if (pill.offsetTop > this.pillElements[0].offsetTop + this.pillElements[0].getBoundingClientRect().height) { + notFittingCount += 1; + } + }); + this.pillsNotFittingCount = notFittingCount; + } + + /* EVENT HANDLERS */ + handleSearchChange(event) { + let searchText = event.target.value; + this.openList(); + this.debounce( + () => this.customSearchHandler ? this.customSearchHandler(searchText) : this.filterOptions(), + this.debounceDelay + ); + } + + handleSearchClick() { + this.handleSearchFocus(); + this.openList(); + } + + handleSearchFocus() { + this.filterOptions(); + this.errorMessage = ''; + } + + handleSearchBlur() { + if (this.inputElement.value && !this.showSelectedValue) { + let matchingValue = this.options.find(option => option.value?.toLowerCase() == this.inputElement.value?.toLowerCase()); + // let matchingValue = this.options.find(option => { + // console.log('searching option: '+ JSON.stringify(option) +', comparing it to '+ this.inputElement.value); + // return option.value?.toLowerCase() == this.inputElement.value?.toLowerCase() + // }); + if (matchingValue) { + this.selectOption(matchingValue.index); + } + } + this.closeList(); + this.reportValidity(); + } + + handleSearchKeydown(event) { + if (this.disabled) { + return; + } + if (event.key === KEYS.DOWN || event.key === KEYS.UP || event.key === KEYS.ENTER) { + if (!this.showList) { + this.openList(); + event.key === KEYS.UP ? this.highlightPreviousOption(this.highlightedOptionIndex) : this.highlightNextOption(this.highlightedOptionIndex); + } else { + if (this.options.some(option => !option.hidden)) { + if (event.key === KEYS.ENTER) { + this.selectOption(this.highlightedOptionIndex); + this.resetSearch(); + this.closeList(); + } else { + event.preventDefault(); + event.stopPropagation(); + event.key === KEYS.UP ? this.highlightPreviousOption(Number(this.highlightedOptionIndex) - 1) : this.highlightNextOption(Number(this.highlightedOptionIndex) + 1); + } + } + } + } + + if (event.key === KEYS.ESCAPE) { + event.preventDefault(); + event.stopPropagation(); + if (this.showSelectedValue) { + this.handleClearClick(); + } else { + this.resetSearch(); + this.closeList(); + } + } + } + + handleOptionSelect(event) { + this.selectOption(event.currentTarget.dataset.index); + } + + handleOptionUnselect(event) { + this.unselectOption(event.target.dataset.index); + } + + handleOptionMouseenter(event) { + this.highlightedOptionIndex = event.currentTarget.dataset.index; + } + + handleOptionMouseleave() { + this.highlightedOptionIndex = undefined; + } + + handleClearClick() { + if (!this.disabled) { + this.values = []; + this.dispatchOptions(); + this.openList(); + } + } + + handleSelectedValueClick() { + if (this.isBaseVariant) { + this.openList(); + this.highlightOption(this.selectedOption.index); + } + } + + handleCollapsePillContainer() { + this.pillContainerIsExpanded = false; + this.resizePillContainer(); + } + + handleExpandPillContainer() { + this.pillContainerIsExpanded = true; + this.resizePillContainer(); + } + + handleListboxScroll(event) { + if (!event.target) + return; + const lastDisplayedOption = this.template.querySelector('.slds-listbox__item:last-child'); + const ul = this.template.querySelector('.slds-listbox'); + let ot = lastDisplayedOption?.offsetTop + if (event.target.scrollTop + event.target.offsetHeight > ot) { + this.numOptionsDisplayed += LOAD_COUNT; + this.filterOptions(); + } + + } + + /* UTILITY FUNCTIONS */ + debounce(fn, wait) { + clearTimeout(this.debounceTimer); + this.debounceTimer = setTimeout(fn, wait); + } + + getComboboxOption(option, index) { + return { + ...option, + index, + get comboboxClass() { + return 'slds-media slds-media_center slds-listbox__option slds-listbox__option_has-meta slds-listbox__option_plain' + (this.hasFocus ? ' slds-has-focus' : ''); + } + } + } + + // Lovingly "borrowed" from https://github.com/salesforce/base-components-recipes/blob/83b87d3772557a22de16f74a047a087a51c4934c/force-app/main/default/lwc/baseCombobox/baseCombobox.js#L836 + scrollIntoViewIfNeeded(element, scrollingParent) { + const parentRect = scrollingParent.getBoundingClientRect(); + const findMeRect = element.getBoundingClientRect(); + if (findMeRect.top <= parentRect.top) { + if (element.offsetTop + findMeRect.height < parentRect.height) { + scrollingParent.scrollTop = 0; + } else { + scrollingParent.scrollTop = element.offsetTop; + } + } else if (findMeRect.bottom >= parentRect.bottom) { + scrollingParent.scrollTop += findMeRect.bottom - parentRect.bottom; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml new file mode 100644 index 0000000..bde6546 --- /dev/null +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js-meta.xml @@ -0,0 +1,14 @@ + + + 52.0 + true + Combobox + + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js new file mode 100644 index 0000000..7af1721 --- /dev/null +++ b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js @@ -0,0 +1,33 @@ +const KEYS = { + ESCAPE: 'Escape', + UP: 'ArrowUp', + DOWN: 'ArrowDown', + ENTER: 'Enter' +} + +const setValuesFromMultipleInput = (values) => { + if (!values) { + return []; + } else { + return Array.isArray(values) ? [...values] : [values]; + } +} + +const setValuesFromSingularInput = (value, delimiter, isMultiSelect) => { + if (!value) { + return []; + } else { + return isMultiSelect ? value.split(delimiter).map(val => val.trim()) : [value]; + } +} + +const includesIgnoreCase = (valueToSearch, valueToSearchFor) => { + if (Array.isArray(valueToSearch)) { + return valueToSearch.map(arrayValue => arrayValue.toLowerCase()).includes(valueToSearchFor.toLowerCase()); + } else { + return valueToSearch.toLowerCase().includes(valueToSearchFor.toLowerCase()); + } + +} + +export { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml new file mode 100644 index 0000000..3f28286 --- /dev/null +++ b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html new file mode 100644 index 0000000..32589e5 --- /dev/null +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js new file mode 100644 index 0000000..df67709 --- /dev/null +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js @@ -0,0 +1,235 @@ +import { LightningElement, api, track, wire } from 'lwc'; +import { getObjectInfo } from 'lightning/uiObjectInfoApi'; +import getObjectFields from '@salesforce/apex/ObjectFieldSelectorController.getObjectFields'; +import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } from 'c/fsc_comboboxUtils'; + +const DATA_TYPE_ICONS = { + Address: 'utility:location', + Boolean: 'utility:check', + ComboBox: 'utility:picklist_type', + Currency: 'utility:currency', + Date: 'utility:date_input', + DateTime: 'utility:date_time', + Double: 'utility:number_input', + Email: 'utility:email', + Int: 'utility:number_input', + Location: 'utility:location', + MultiPicklist: 'utility:multi_picklist', + Percent: 'utility:percent', + Phone: 'utility:phone_portrait', + Picklist: 'utility:picklist_type', + Reference: 'utility:record_lookup', + Time: 'utility:clock', + Url: 'utility:link' +} +const DEFAULT_ICON = 'utility:text'; + +const INVALID_TYPE_ERROR = 'INVALID_TYPE'; + +export default class Fsc_fieldSelector2 extends LightningElement { + @api name; + @api allowMultiselect = false; + @api required = false; + @api label = 'Select Field'; + @api showSelectedCount; + @api publicClass; + @api publicStyle; + @api placeholder = 'Type to search fields'; + @api fieldLevelHelp; + @api valueDelimiter = ','; + @api fieldTypeDelimiter = ';'; // Sometimes an array of availableFieldTypes will contain more than one field type value in a single element, so this allows a separate delimiter to be used to split within the element + @api hideIcons = false; + @api isLoading = false; + @api disabled = false; + @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). + @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. + @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + @api allowReferenceLookups = false; + @track fields = []; + @track _values = []; + @track _availableFieldTypes = []; + @track _availableReferenceTypes = []; + + @api builderContext; + + fieldTypes = transformConstantObject(FIELD_TYPES); + _objectName; + isNotFirstObjectLoad; + errorMessage; + + @api + get objectName() { + return this._objectName; + } + set objectName(value) { + this._objectName = value; + if (!this.objectName) { + this.clearValues(); + } + } + + @api + get values() { + return this._values || []; + } + set values(values) { + this._values = setValuesFromMultipleInput(values); + } + @track _values = []; + + @api + get value() { + return this.values.join(this.valueDelimiter); + } + set value(value) { + this.values = setValuesFromSingularInput(value, this.valueDelimiter, this.allowMultiselect); + } + + @api + get availableFieldTypes() { + return this._availableFieldTypes; + } + set availableFieldTypes(value) { + if (!value) { + this._availableFieldTypes = []; + } else if (Array.isArray(value)) { + this._availableFieldTypes = value; + } else { + let types = []; + value.split(this.valueDelimiter).forEach(value => { + types.push(...value.split(this.fieldTypeDelimiter).map(fieldType => fieldType.toLowerCase())); + }) + this._availableFieldTypes = types; + } + } + + @api + get availableReferenceTypes() { + return this._availableReferenceTypes; + } + set availableReferenceTypes(value) { + if (!value) { + this.values = []; + } else { + this._availableReferenceTypes = value.split(this.valueDelimiter).map(val => val.trim()); + } + } + + @api + reportValidity() { + return this.template.querySelector('c-fsc_combobox').reportValidity(); + } + + @api + validate() { + // console.log('in fieldSelector validate, returning '+ JSON.stringify(this.template.querySelector('c-fsc_combobox').validate())); + return this.template.querySelector('c-fsc_combobox').validate(); + } + + get isLoadingOrDisabled() { + return this.isLoading || this.disabled || !this.objectName; + } + + get computedPlaceholder() { + if (!this.objectName) { + return 'No object selected, please select an object'; + } else if (this.isLoading) { + return 'Loading...'; + } else { + return this.placeholder; + } + } + + @wire(getObjectInfo, { objectApiName: '$objectName' }) + handleGetObjectInfo({ error, data }) { + if (error) { + console.log('Fieldselector error: ' + JSON.stringify(error)); + if (error.body.errorCode === INVALID_TYPE_ERROR) { + this.loadObjectInfo(); + } else { + this.errorMessage = 'Unknown error'; + if (Array.isArray(error.body)) { + this.errorMessage = error.body.map(e => e.message).join(', '); + } else if (typeof error.body.message === 'string') { + this.errorMessage = error.body.message; + } + } + } else if (data) { + console.log(JSON.stringify(Object.values(data.fields).filter(field => field.relationshipName)[0])); + this.processFields(Object.values(data.fields)); + } else { + console.log('neither data nor error'); + } + this.isLoading = false; + } + + loadObjectInfo() { + if (!this.objectName || this.isNotFirstObjectLoad) { + this.clearValues(); + } + if (this.objectName) { + this.isLoading = true; + this.disabled = false; + this.isNotFirstObjectLoad = true; + getObjectFields({ objectName: this.objectName }) + .then(result => { + this.processFields(result.fields); + }).catch(error => { + console.log('getObjectFields error: ' + JSON.stringify(error)); + this.errorMessage = error.errorMessage || 'Unknown error'; + }).finally(() => { + this.isLoading = false; + console.log('finished loadObjectInfo'); + }) + } + } + + /* EVENT HANDLERS */ + handleComboboxChange(event) { + this.values = event.detail.values; + this.dispatchFields(); + } + + /* ACTION FUNCTIONS */ + processFields(fields) { + if (this.availableFieldTypes?.length) { + fields = fields.filter(field => includesIgnoreCase(this.availableFieldTypes, field.dataType)); + if (this.availableReferenceTypes?.length) { + fields = fields.filter(field => !field.referenceToInfos.length || field.referenceToInfos.some(ref => includesIgnoreCase(this.availableReferenceTypes, ref.apiName))); + } + } + this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, this.hideIcons ? null : this.getIconFromDataType(field.dataType))); + this.fields.sort((a, b) => { + return a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1; + }); + + } + + clearValues() { + console.log('in clearValues'); + if (this.values.length) { + console.log('actually clearing because there are values to clear (' + this.values + ')'); + this.values = []; + this.dispatchFields(); + } + } + + dispatchFields() { + let detail = { + value: this.value, + values: this.values, + } + this.dispatchEvent(new CustomEvent('change', { detail })); + } + + /* UTILITY FUNCTIONS */ + getIconFromDataType(type) { + let matchingType = this.fieldTypes.options.find(fieldType => includesIgnoreCase(fieldType.value.split(this.fieldTypeDelimiter), type)); + return matchingType?.icon || DEFAULT_ICON; + } + + newField(label, sublabel, value, icon) { + return { label, sublabel, value, icon } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml new file mode 100644 index 0000000..884004a --- /dev/null +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js new file mode 100644 index 0000000..8e5e25a --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js @@ -0,0 +1,58 @@ +const FIELD_TYPES = { + REFERENCE: { label: 'Lookup/Master-Detail', value: 'Reference', icon: 'utility:record_lookup' }, + ADDRESS: { label: 'Address', value: 'Address', icon: 'utility:location' }, + CHECKBOX: { label: 'Checkbox', value: 'Boolean', icon: 'utility:check' }, + CURRENCY: { label: 'Currency', value: 'Currency', icon: 'utility:currency' }, + DATE: { label: 'Date', value: 'Date', icon: 'utility:date_input' }, + DATETIME: { label: 'Date/Time', value: 'DateTime', icon: 'utility:date_time' }, + EMAIL: { label: 'Email', value: 'Email', icon: 'utility:email' }, + LOCATION: { label: 'Geolocation', value: 'Location', icon: 'utility:location' }, + NUMBER: { label: 'Number', value: 'Integer;Double;Int;Long', icon: 'utility:number_input' }, + PERCENT: { label: 'Percent', value: 'Percent', icon: 'utility:percent' }, + PHONE: { label: 'Phone Number', value: 'Phone', icon: 'utility:phone_portrait' }, + PICKLIST: { label: 'Picklist', value: 'Picklist;ComboBox', icon: 'utility:picklist_type' }, + MULTIPICKLIST: { label: 'Picklist (Multi-Select)', value: 'MultiPicklist', icon: 'utility:multi_picklist' }, + TEXT: { label: 'Text', value: 'String', icon: 'utility:text' }, + TEXTAREA: { label: 'Text Area', value: 'TextArea', icon: 'utility:textbox' }, + TEXTENCRYPTED: { label: 'Text (Encrypted)', value: 'EncryptedString', icon: 'utility:hide' }, + TIME: { label: 'Time', value: 'Time', icon: 'utility:clock' }, + URL: { label: 'URL', value: 'URL', icon: 'utility:link' }, +}; + +const DISPLAY_TYPE_OPTIONS = { + OBJECT: { label: 'Just Object(s)', value: 'object' }, + FIELD: { label: 'Just Field(s)', value: 'field' }, + BOTH: { label: 'Both', value: 'both', default: true } +} + +const AVAILABLE_OBJECT_OPTIONS = { + BOTH: { label: 'Custom and Standard Objects', value: 'both', subcategories: ['standard', 'custom'], default: true }, + STANDARD: { label: 'Standard Objects Only', value: 'standard' }, + CUSTOM: { label: 'Custom Objects Only', value: 'custom' }, + ALL: { label: 'ALL Objects (advanced)', value: 'all', subcategories: ['standard', 'custom', 'ancillary'] }, + ANCILLARY: { label: 'Ancillary Objects Only', value: 'ancillary', hide: true }, + SPECIFIC: { label: 'Select Specific Objects', value: 'specific' } +} + +const LAYOUT_OPTIONS = { + VERTICAL: { label: 'Vertical', value: 'vertical', default: true}, + HORIZONTAL: { label: 'Horizontal', value: 'horizontal' }, +} + +const transformConstantObject = (constant) => { + return { + list: constant, + get options() { return Object.values(this.list).filter(option => !option.hide); }, + get default() { return this.options.find(option => option.default); }, + findFromValue: function (value) { + let entry = this.options.find(option => option.value == value); + return entry || this.default; + }, + findFromLabel: function (label) { + let entry = this.options.find(option => option.label == label); + return entry || this.default; + } + } +} + +export { FIELD_TYPES, DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, LAYOUT_OPTIONS, transformConstantObject } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml new file mode 100644 index 0000000..3f28286 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelectorUtils/fsc_objectFieldSelectorUtils.js-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html new file mode 100644 index 0000000..6d62dd2 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js new file mode 100644 index 0000000..172bf36 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js @@ -0,0 +1,157 @@ +import { LightningElement, wire, track, api } from 'lwc'; +import getObjects from '@salesforce/apex/ObjectFieldSelectorController.getObjects'; +import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_comboboxUtils'; + +const ANCILLARY_SUFFIXES = ['Feed', 'Tag', 'Share', 'ChangeEvent', 'History']; +export default class Fsc_objectSelector extends LightningElement { + availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); + + @api name; + @api allowMultiselect = false; + @api required = false; + @api label = 'Select Object'; + @api placeholder = 'Type to search objects'; + @api showSelectedCount; + @api publicClass; + @api publicStyle; + @api fieldLevelHelp; + @api variant; + @api hideIcons = false; + @api valueDelimiter = ','; + @api isLoading = false; + @api disabled = false; + @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). + @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. + @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + // @api availableObjectSelection = this.availableObjectOptions.default?.value; + @api availableObjects = []; + + @api builderContext; + + hasConnected = false; + @track allOptions = []; + @track loadedCategories = []; + + @api + get values() { + return this._values || []; + } + set values(values) { + this._values = setValuesFromMultipleInput(values); + } + @track _values = []; + + @api + get value() { + return this.values.join(this.valueDelimiter); + } + set value(value) { + this.values = setValuesFromSingularInput(value, this.valueDelimiter, this.allowMultiselect); + } + + @api + get availableObjectSelection() { + return this._availableObjectSelection; + } + set availableObjectSelection(value) { + console.log(' in set availableObjectSelection to ' + value); + this._availableObjectSelection = value; + if (this.hasConnected && this.values.length) { + this.values = []; + this.dispatchObjects(); + } + // if (!this.loadedCategories.includes(this.availableObjectSelection)) { + // this.loadObjectCategory(this.availableObjectSelection); + // } + } + _availableObjectSelection = this.availableObjectOptions.default?.value; + + get objectOptions() { + return this.allOptions.filter(option => { + if (this.availableObjectSelection === AVAILABLE_OBJECT_OPTIONS.SPECIFIC.value) { + return this.availableObjects?.includes(option.value); + } else { + return this.matchesObjectCategory(option.category); + } + }); + } + + get computedPlaceholder() { + return this.isLoading ? 'Loading...' : this.placeholder; + } + + // @api + // get availableObjects() { + // return this._availableObjects; + // } + // set availableObjects(value) { + // this._availableObjects = value; + // if(this.hasConnected) + // this.loadObjects(); + // } + // _availableObjects = [] + + addObjectOptions(options, category) { + let newOptions = options.map(objectType => { + return { + category, + label: objectType.label, + sublabel: objectType.value, + value: objectType.value, + } + }); + this.allOptions = [...this.allOptions, ...newOptions].sort((a, b) => { + return a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1; + }); + } + + loadObjectCategory(category) { + if (!this.value) { + this.isLoading = true; + } + getObjects({ selectionType: category }) + .then(result => { + this.addObjectOptions(result.objects, category); + this.isLoading = false; + }); + } + + @api + reportValidity() { + return this.template.querySelector('c-fsc_combobox').reportValidity(); + } + + @api + validate() { + return this.template.querySelector('c-fsc_combobox').validate(); + } + + connectedCallback() { + this.hasConnected = true; + let initialLoadCategories = [AVAILABLE_OBJECT_OPTIONS.STANDARD.value, AVAILABLE_OBJECT_OPTIONS.CUSTOM.value, AVAILABLE_OBJECT_OPTIONS.ANCILLARY.value]; + initialLoadCategories.forEach(category => { + this.loadObjectCategory(category); + }); + } + + handleComboboxChange(event) { + this.values = event.detail.values; + this.dispatchObjects(); + } + + dispatchObjects() { + let detail = { + value: this.value, + values: this.values, + } + console.log('dispatching objects', JSON.stringify(detail)); + this.dispatchEvent(new CustomEvent('change', { detail })); + } + + matchesObjectCategory(category) { + return category === this.availableObjectSelection || + this.availableObjectSelection === AVAILABLE_OBJECT_OPTIONS.ALL.value || + (this.availableObjectSelection === AVAILABLE_OBJECT_OPTIONS.BOTH.value && (category === AVAILABLE_OBJECT_OPTIONS.STANDARD.value || category === AVAILABLE_OBJECT_OPTIONS.CUSTOM.value)) + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml new file mode 100644 index 0000000..ba22d67 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js-meta.xml @@ -0,0 +1,15 @@ + + + 54.0 + true + + lightning__FlowScreen + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/iconSelector/iconSelector.html b/force-app/main/default/lwc/iconSelector/iconSelector.html new file mode 100644 index 0000000..b8a5e2f --- /dev/null +++ b/force-app/main/default/lwc/iconSelector/iconSelector.html @@ -0,0 +1,45 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/iconSelector/iconSelector.js b/force-app/main/default/lwc/iconSelector/iconSelector.js new file mode 100644 index 0000000..3f199ab --- /dev/null +++ b/force-app/main/default/lwc/iconSelector/iconSelector.js @@ -0,0 +1,1406 @@ +import { LightningElement, track, api } from 'lwc'; + +const TABLE_STYLE = "height: 400px; width:99%"; + +// Icons updated 6/3/21 +// Lightning Design System Release 2.15.8 - May 27, 2021 + +const ACTION_ICONS = [ + { 'iconName': 'action:add_contact', 'id': 'action:add_contact' }, + { 'iconName': 'action:add_file', 'id': 'action:add_file' }, + { 'iconName': 'action:add_photo_video', 'id': 'action:add_photo_video' }, + { 'iconName': 'action:add_relationship', 'id': 'action:add_relationship' }, + { 'iconName': 'action:adjust_value', 'id': 'action:adjust_value' }, + { 'iconName': 'action:announcement', 'id': 'action:announcement' }, + { 'iconName': 'action:apex', 'id': 'action:apex' }, + { 'iconName': 'action:approval', 'id': 'action:approval' }, + { 'iconName': 'action:back', 'id': 'action:back' }, + { 'iconName': 'action:bug', 'id': 'action:bug' }, + { 'iconName': 'action:call', 'id': 'action:call' }, + { 'iconName': 'action:canvas', 'id': 'action:canvas' }, + { 'iconName': 'action:change_owner', 'id': 'action:change_owner' }, + { 'iconName': 'action:change_record_type', 'id': 'action:change_record_type' }, + { 'iconName': 'action:check', 'id': 'action:check' }, + { 'iconName': 'action:clone', 'id': 'action:clone' }, + { 'iconName': 'action:close', 'id': 'action:close' }, + { 'iconName': 'action:defer', 'id': 'action:defer' }, + { 'iconName': 'action:delete', 'id': 'action:delete' }, + { 'iconName': 'action:description', 'id': 'action:description' }, + { 'iconName': 'action:dial_in', 'id': 'action:dial_in' }, + { 'iconName': 'action:download', 'id': 'action:download' }, + { 'iconName': 'action:edit_groups', 'id': 'action:edit_groups' }, + { 'iconName': 'action:edit_relationship', 'id': 'action:edit_relationship' }, + { 'iconName': 'action:edit', 'id': 'action:edit' }, + { 'iconName': 'action:email', 'id': 'action:email' }, + { 'iconName': 'action:fallback', 'id': 'action:fallback' }, + { 'iconName': 'action:filter', 'id': 'action:filter' }, + { 'iconName': 'action:flow', 'id': 'action:flow' }, + { 'iconName': 'action:follow', 'id': 'action:follow' }, + { 'iconName': 'action:following', 'id': 'action:following' }, + { 'iconName': 'action:freeze_user', 'id': 'action:freeze_user' }, + { 'iconName': 'action:goal', 'id': 'action:goal' }, + { 'iconName': 'action:google_news', 'id': 'action:google_news' }, + { 'iconName': 'action:info', 'id': 'action:info' }, + { 'iconName': 'action:join_group', 'id': 'action:join_group' }, + { 'iconName': 'action:lead_convert', 'id': 'action:lead_convert' }, + { 'iconName': 'action:leave_group', 'id': 'action:leave_group' }, + { 'iconName': 'action:log_a_call', 'id': 'action:log_a_call' }, + { 'iconName': 'action:log_event', 'id': 'action:log_event' }, + { 'iconName': 'action:manage_perm_sets', 'id': 'action:manage_perm_sets' }, + { 'iconName': 'action:map', 'id': 'action:map' }, + { 'iconName': 'action:more', 'id': 'action:more' }, + { 'iconName': 'action:new_account', 'id': 'action:new_account' }, + { 'iconName': 'action:new_campaign', 'id': 'action:new_campaign' }, + { 'iconName': 'action:new_case', 'id': 'action:new_case' }, + { 'iconName': 'action:new_child_case', 'id': 'action:new_child_case' }, + { 'iconName': 'action:new_contact', 'id': 'action:new_contact' }, + { 'iconName': 'action:new_event', 'id': 'action:new_event' }, + { 'iconName': 'action:new_group', 'id': 'action:new_group' }, + { 'iconName': 'action:new_lead', 'id': 'action:new_lead' }, + { 'iconName': 'action:new_note', 'id': 'action:new_note' }, + { 'iconName': 'action:new_notebook', 'id': 'action:new_notebook' }, + { 'iconName': 'action:new_opportunity', 'id': 'action:new_opportunity' }, + { 'iconName': 'action:new_person_account', 'id': 'action:new_person_account' }, + { 'iconName': 'action:new_task', 'id': 'action:new_task' }, + { 'iconName': 'action:new', 'id': 'action:new' }, + { 'iconName': 'action:password_unlock', 'id': 'action:password_unlock' }, + { 'iconName': 'action:preview', 'id': 'action:preview' }, + { 'iconName': 'action:priority', 'id': 'action:priority' }, + { 'iconName': 'action:question_post_action', 'id': 'action:question_post_action' }, + { 'iconName': 'action:quote', 'id': 'action:quote' }, + { 'iconName': 'action:recall', 'id': 'action:recall' }, + { 'iconName': 'action:record', 'id': 'action:record' }, + { 'iconName': 'action:refresh', 'id': 'action:refresh' }, + { 'iconName': 'action:reject', 'id': 'action:reject' }, + { 'iconName': 'action:remove_relationship', 'id': 'action:remove_relationship' }, + { 'iconName': 'action:remove', 'id': 'action:remove' }, + { 'iconName': 'action:reset_password', 'id': 'action:reset_password' }, + { 'iconName': 'action:script', 'id': 'action:script' }, + { 'iconName': 'action:share_file', 'id': 'action:share_file' }, + { 'iconName': 'action:share_link', 'id': 'action:share_link' }, + { 'iconName': 'action:share_poll', 'id': 'action:share_poll' }, + { 'iconName': 'action:share_post', 'id': 'action:share_post' }, + { 'iconName': 'action:share_thanks', 'id': 'action:share_thanks' }, + { 'iconName': 'action:share', 'id': 'action:share' }, + { 'iconName': 'action:sort', 'id': 'action:sort' }, + { 'iconName': 'action:submit_for_approval', 'id': 'action:submit_for_approval' }, + { 'iconName': 'action:update_status', 'id': 'action:update_status' }, + { 'iconName': 'action:update', 'id': 'action:update' }, + { 'iconName': 'action:upload', 'id': 'action:upload' }, + { 'iconName': 'action:user_activation', 'id': 'action:user_activation' }, + { 'iconName': 'action:user', 'id': 'action:user' }, + { 'iconName': 'action:view_relationship', 'id': 'action:view_relationship' }, + { 'iconName': 'action:web_link', 'id': 'action:web_link' } +]; + +const CUSTOM_ICONS = [{ 'iconName': 'custom:custom1', 'id': 'custom:custom1' }, + { 'iconName': 'custom:custom2', 'id': 'custom:custom2' }, + { 'iconName': 'custom:custom3', 'id': 'custom:custom3' }, + { 'iconName': 'custom:custom4', 'id': 'custom:custom4' }, + { 'iconName': 'custom:custom5', 'id': 'custom:custom5' }, + { 'iconName': 'custom:custom6', 'id': 'custom:custom6' }, + { 'iconName': 'custom:custom7', 'id': 'custom:custom7' }, + { 'iconName': 'custom:custom8', 'id': 'custom:custom8' }, + { 'iconName': 'custom:custom9', 'id': 'custom:custom9' }, + { 'iconName': 'custom:custom10', 'id': 'custom:custom10' }, + { 'iconName': 'custom:custom11', 'id': 'custom:custom11' }, + { 'iconName': 'custom:custom12', 'id': 'custom:custom12' }, + { 'iconName': 'custom:custom13', 'id': 'custom:custom13' }, + { 'iconName': 'custom:custom14', 'id': 'custom:custom14' }, + { 'iconName': 'custom:custom15', 'id': 'custom:custom15' }, + { 'iconName': 'custom:custom16', 'id': 'custom:custom16' }, + { 'iconName': 'custom:custom17', 'id': 'custom:custom17' }, + { 'iconName': 'custom:custom18', 'id': 'custom:custom18' }, + { 'iconName': 'custom:custom19', 'id': 'custom:custom19' }, + { 'iconName': 'custom:custom20', 'id': 'custom:custom20' }, + { 'iconName': 'custom:custom21', 'id': 'custom:custom21' }, + { 'iconName': 'custom:custom22', 'id': 'custom:custom22' }, + { 'iconName': 'custom:custom23', 'id': 'custom:custom23' }, + { 'iconName': 'custom:custom24', 'id': 'custom:custom24' }, + { 'iconName': 'custom:custom25', 'id': 'custom:custom25' }, + { 'iconName': 'custom:custom26', 'id': 'custom:custom26' }, + { 'iconName': 'custom:custom27', 'id': 'custom:custom27' }, + { 'iconName': 'custom:custom28', 'id': 'custom:custom28' }, + { 'iconName': 'custom:custom29', 'id': 'custom:custom29' }, + { 'iconName': 'custom:custom30', 'id': 'custom:custom30' }, + { 'iconName': 'custom:custom31', 'id': 'custom:custom31' }, + { 'iconName': 'custom:custom32', 'id': 'custom:custom32' }, + { 'iconName': 'custom:custom33', 'id': 'custom:custom33' }, + { 'iconName': 'custom:custom34', 'id': 'custom:custom34' }, + { 'iconName': 'custom:custom35', 'id': 'custom:custom35' }, + { 'iconName': 'custom:custom36', 'id': 'custom:custom36' }, + { 'iconName': 'custom:custom37', 'id': 'custom:custom37' }, + { 'iconName': 'custom:custom38', 'id': 'custom:custom38' }, + { 'iconName': 'custom:custom39', 'id': 'custom:custom39' }, + { 'iconName': 'custom:custom40', 'id': 'custom:custom40' }, + { 'iconName': 'custom:custom41', 'id': 'custom:custom41' }, + { 'iconName': 'custom:custom42', 'id': 'custom:custom42' }, + { 'iconName': 'custom:custom43', 'id': 'custom:custom43' }, + { 'iconName': 'custom:custom44', 'id': 'custom:custom44' }, + { 'iconName': 'custom:custom45', 'id': 'custom:custom45' }, + { 'iconName': 'custom:custom46', 'id': 'custom:custom46' }, + { 'iconName': 'custom:custom47', 'id': 'custom:custom47' }, + { 'iconName': 'custom:custom48', 'id': 'custom:custom48' }, + { 'iconName': 'custom:custom49', 'id': 'custom:custom49' }, + { 'iconName': 'custom:custom50', 'id': 'custom:custom50' }, + { 'iconName': 'custom:custom51', 'id': 'custom:custom51' }, + { 'iconName': 'custom:custom52', 'id': 'custom:custom52' }, + { 'iconName': 'custom:custom53', 'id': 'custom:custom53' }, + { 'iconName': 'custom:custom54', 'id': 'custom:custom54' }, + { 'iconName': 'custom:custom55', 'id': 'custom:custom55' }, + { 'iconName': 'custom:custom56', 'id': 'custom:custom56' }, + { 'iconName': 'custom:custom57', 'id': 'custom:custom57' }, + { 'iconName': 'custom:custom58', 'id': 'custom:custom58' }, + { 'iconName': 'custom:custom59', 'id': 'custom:custom59' }, + { 'iconName': 'custom:custom60', 'id': 'custom:custom60' }, + { 'iconName': 'custom:custom61', 'id': 'custom:custom61' }, + { 'iconName': 'custom:custom62', 'id': 'custom:custom62' }, + { 'iconName': 'custom:custom63', 'id': 'custom:custom63' }, + { 'iconName': 'custom:custom64', 'id': 'custom:custom64' }, + { 'iconName': 'custom:custom65', 'id': 'custom:custom65' }, + { 'iconName': 'custom:custom66', 'id': 'custom:custom66' }, + { 'iconName': 'custom:custom67', 'id': 'custom:custom67' }, + { 'iconName': 'custom:custom68', 'id': 'custom:custom68' }, + { 'iconName': 'custom:custom69', 'id': 'custom:custom69' }, + { 'iconName': 'custom:custom70', 'id': 'custom:custom70' }, + { 'iconName': 'custom:custom71', 'id': 'custom:custom71' }, + { 'iconName': 'custom:custom72', 'id': 'custom:custom72' }, + { 'iconName': 'custom:custom73', 'id': 'custom:custom73' }, + { 'iconName': 'custom:custom74', 'id': 'custom:custom74' }, + { 'iconName': 'custom:custom75', 'id': 'custom:custom75' }, + { 'iconName': 'custom:custom76', 'id': 'custom:custom76' }, + { 'iconName': 'custom:custom77', 'id': 'custom:custom77' }, + { 'iconName': 'custom:custom78', 'id': 'custom:custom78' }, + { 'iconName': 'custom:custom79', 'id': 'custom:custom79' }, + { 'iconName': 'custom:custom80', 'id': 'custom:custom80' }, + { 'iconName': 'custom:custom81', 'id': 'custom:custom81' }, + { 'iconName': 'custom:custom82', 'id': 'custom:custom82' }, + { 'iconName': 'custom:custom83', 'id': 'custom:custom83' }, + { 'iconName': 'custom:custom84', 'id': 'custom:custom84' }, + { 'iconName': 'custom:custom85', 'id': 'custom:custom85' }, + { 'iconName': 'custom:custom86', 'id': 'custom:custom86' }, + { 'iconName': 'custom:custom87', 'id': 'custom:custom87' }, + { 'iconName': 'custom:custom88', 'id': 'custom:custom88' }, + { 'iconName': 'custom:custom89', 'id': 'custom:custom89' }, + { 'iconName': 'custom:custom90', 'id': 'custom:custom90' }, + { 'iconName': 'custom:custom91', 'id': 'custom:custom91' }, + { 'iconName': 'custom:custom92', 'id': 'custom:custom92' }, + { 'iconName': 'custom:custom93', 'id': 'custom:custom93' }, + { 'iconName': 'custom:custom94', 'id': 'custom:custom94' }, + { 'iconName': 'custom:custom95', 'id': 'custom:custom95' }, + { 'iconName': 'custom:custom96', 'id': 'custom:custom96' }, + { 'iconName': 'custom:custom97', 'id': 'custom:custom97' }, + { 'iconName': 'custom:custom98', 'id': 'custom:custom98' }, + { 'iconName': 'custom:custom99', 'id': 'custom:custom99' }, + { 'iconName': 'custom:custom100', 'id': 'custom:custom100' }, + { 'iconName': 'custom:custom101', 'id': 'custom:custom101' }, + { 'iconName': 'custom:custom102', 'id': 'custom:custom102' }, + { 'iconName': 'custom:custom103', 'id': 'custom:custom103' }, + { 'iconName': 'custom:custom104', 'id': 'custom:custom104' }, + { 'iconName': 'custom:custom105', 'id': 'custom:custom105' }, + { 'iconName': 'custom:custom106', 'id': 'custom:custom106' }, + { 'iconName': 'custom:custom107', 'id': 'custom:custom107' }, + { 'iconName': 'custom:custom108', 'id': 'custom:custom108' }, + { 'iconName': 'custom:custom109', 'id': 'custom:custom109' }, + { 'iconName': 'custom:custom110', 'id': 'custom:custom110' }, + { 'iconName': 'custom:custom111', 'id': 'custom:custom111' }, + { 'iconName': 'custom:custom112', 'id': 'custom:custom112' }, + { 'iconName': 'custom:custom113', 'id': 'custom:custom113' } +] + +const STANDARD_ICONS = [ +    { 'iconName': 'standard:account', 'id': 'standard:account' }, +    { 'iconName': 'standard:action_list_component', 'id': 'standard:action_list_component' }, +    { 'iconName': 'standard:actions_and_buttons', 'id': 'standard:actions_and_buttons' }, +    { 'iconName': 'standard:activation_target', 'id': 'standard:activation_target' }, +    { 'iconName': 'standard:activations', 'id': 'standard:activations' }, +    { 'iconName': 'standard:address', 'id': 'standard:address' }, +    { 'iconName': 'standard:agent_home', 'id': 'standard:agent_home' }, +    { 'iconName': 'standard:agent_session', 'id': 'standard:agent_session' }, +    { 'iconName': 'standard:aggregation_policy', 'id': 'standard:aggregation_policy' }, +    { 'iconName': 'standard:all', 'id': 'standard:all' }, +    { 'iconName': 'standard:announcement', 'id': 'standard:announcement' }, +    { 'iconName': 'standard:answer_best', 'id': 'standard:answer_best' }, +    { 'iconName': 'standard:answer_private', 'id': 'standard:answer_private' }, +    { 'iconName': 'standard:answer_public', 'id': 'standard:answer_public' }, +    { 'iconName': 'standard:apex', 'id': 'standard:apex' }, +    { 'iconName': 'standard:apex_plugin', 'id': 'standard:apex_plugin' }, +    { 'iconName': 'standard:app', 'id': 'standard:app' }, +    { 'iconName': 'standard:approval', 'id': 'standard:approval' }, +    { 'iconName': 'standard:apps', 'id': 'standard:apps' }, +    { 'iconName': 'standard:apps_admin', 'id': 'standard:apps_admin' }, +    { 'iconName': 'standard:article', 'id': 'standard:article' }, +    { 'iconName': 'standard:asset_action', 'id': 'standard:asset_action' }, +    { 'iconName': 'standard:asset_action_source', 'id': 'standard:asset_action_source' }, +    { 'iconName': 'standard:asset_downtime_period', 'id': 'standard:asset_downtime_period' }, +    { 'iconName': 'standard:asset_object', 'id': 'standard:asset_object' }, +    { 'iconName': 'standard:asset_relationship', 'id': 'standard:asset_relationship' }, +    { 'iconName': 'standard:asset_state_period', 'id': 'standard:asset_state_period' }, +    { 'iconName': 'standard:asset_warranty', 'id': 'standard:asset_warranty' }, +    { 'iconName': 'standard:assigned_resource', 'id': 'standard:assigned_resource' }, +    { 'iconName': 'standard:assignment', 'id': 'standard:assignment' }, +    { 'iconName': 'standard:avatar', 'id': 'standard:avatar' }, +    { 'iconName': 'standard:avatar_loading', 'id': 'standard:avatar_loading' }, +    { 'iconName': 'standard:bot', 'id': 'standard:bot' }, +    { 'iconName': 'standard:bot_training', 'id': 'standard:bot_training' }, +    { 'iconName': 'standard:branch_merge', 'id': 'standard:branch_merge' }, +    { 'iconName': 'standard:brand', 'id': 'standard:brand' }, +    { 'iconName': 'standard:bundle_config', 'id': 'standard:bundle_config' }, +    { 'iconName': 'standard:bundle_policy', 'id': 'standard:bundle_policy' }, +    { 'iconName': 'standard:business_hours', 'id': 'standard:business_hours' }, +    { 'iconName': 'standard:buyer_account', 'id': 'standard:buyer_account' }, +    { 'iconName': 'standard:buyer_group', 'id': 'standard:buyer_group' }, +    { 'iconName': 'standard:calculated_insights', 'id': 'standard:calculated_insights' }, +    { 'iconName': 'standard:calibration', 'id': 'standard:calibration' }, +    { 'iconName': 'standard:call', 'id': 'standard:call' }, +    { 'iconName': 'standard:call_coaching', 'id': 'standard:call_coaching' }, +    { 'iconName': 'standard:call_history', 'id': 'standard:call_history' }, +    { 'iconName': 'standard:campaign', 'id': 'standard:campaign' }, +    { 'iconName': 'standard:campaign_members', 'id': 'standard:campaign_members' }, +    { 'iconName': 'standard:cancel_checkout', 'id': 'standard:cancel_checkout' }, +    { 'iconName': 'standard:canvas', 'id': 'standard:canvas' }, +    { 'iconName': 'standard:capacity_plan', 'id': 'standard:capacity_plan' }, +    { 'iconName': 'standard:care_request_reviewer', 'id': 'standard:care_request_reviewer' }, +    { 'iconName': 'standard:carousel', 'id': 'standard:carousel' }, +    { 'iconName': 'standard:case', 'id': 'standard:case' }, +    { 'iconName': 'standard:case_change_status', 'id': 'standard:case_change_status' }, +    { 'iconName': 'standard:case_comment', 'id': 'standard:case_comment' }, +    { 'iconName': 'standard:case_email', 'id': 'standard:case_email' }, +    { 'iconName': 'standard:case_log_a_call', 'id': 'standard:case_log_a_call' }, +    { 'iconName': 'standard:case_milestone', 'id': 'standard:case_milestone' }, +    { 'iconName': 'standard:case_transcript', 'id': 'standard:case_transcript' }, +    { 'iconName': 'standard:case_wrap_up', 'id': 'standard:case_wrap_up' }, +    { 'iconName': 'standard:catalog', 'id': 'standard:catalog' }, +    { 'iconName': 'standard:category', 'id': 'standard:category' }, +    { 'iconName': 'standard:channel_program_history', 'id': 'standard:channel_program_history' }, +    { 'iconName': 'standard:channel_program_levels', 'id': 'standard:channel_program_levels' }, +    { 'iconName': 'standard:channel_program_members', 'id': 'standard:channel_program_members' }, +    { 'iconName': 'standard:channel_programs', 'id': 'standard:channel_programs' }, +    { 'iconName': 'standard:chart', 'id': 'standard:chart' }, +    { 'iconName': 'standard:checkout', 'id': 'standard:checkout' }, +    { 'iconName': 'standard:choice', 'id': 'standard:choice' }, +    { 'iconName': 'standard:client', 'id': 'standard:client' }, +    { 'iconName': 'standard:cms', 'id': 'standard:cms' }, +    { 'iconName': 'standard:coaching', 'id': 'standard:coaching' }, +    { 'iconName': 'standard:code_playground', 'id': 'standard:code_playground' }, +    { 'iconName': 'standard:collection', 'id': 'standard:collection' }, +    { 'iconName': 'standard:collection_variable', 'id': 'standard:collection_variable' }, +    { 'iconName': 'standard:connected_apps', 'id': 'standard:connected_apps' }, +    { 'iconName': 'standard:constant', 'id': 'standard:constant' }, +    { 'iconName': 'standard:contact', 'id': 'standard:contact' }, +    { 'iconName': 'standard:contact_list', 'id': 'standard:contact_list' }, +    { 'iconName': 'standard:contact_request', 'id': 'standard:contact_request' }, +    { 'iconName': 'standard:contract', 'id': 'standard:contract' }, +    { 'iconName': 'standard:contract_line_item', 'id': 'standard:contract_line_item' }, +    { 'iconName': 'standard:currency', 'id': 'standard:currency' }, +    { 'iconName': 'standard:currency_input', 'id': 'standard:currency_input' }, +    { 'iconName': 'standard:custom', 'id': 'standard:custom' }, +    { 'iconName': 'standard:custom_component_task', 'id': 'standard:custom_component_task' }, +    { 'iconName': 'standard:custom_notification', 'id': 'standard:custom_notification' }, +    { 'iconName': 'standard:customer_360', 'id': 'standard:customer_360' }, +    { 'iconName': 'standard:customer_lifecycle_analytics', 'id': 'standard:customer_lifecycle_analytics' }, +    { 'iconName': 'standard:customer_portal_users', 'id': 'standard:customer_portal_users' }, +    { 'iconName': 'standard:customers', 'id': 'standard:customers' }, +    { 'iconName': 'standard:dashboard', 'id': 'standard:dashboard' }, +    { 'iconName': 'standard:dashboard_ea', 'id': 'standard:dashboard_ea' }, +    { 'iconName': 'standard:data_integration_hub', 'id': 'standard:data_integration_hub' }, +    { 'iconName': 'standard:data_mapping', 'id': 'standard:data_mapping' }, +    { 'iconName': 'standard:data_model', 'id': 'standard:data_model' }, +    { 'iconName': 'standard:data_streams', 'id': 'standard:data_streams' }, +    { 'iconName': 'standard:datadotcom', 'id': 'standard:datadotcom' }, +    { 'iconName': 'standard:dataset', 'id': 'standard:dataset' }, +    { 'iconName': 'standard:date_input', 'id': 'standard:date_input' }, +    { 'iconName': 'standard:date_time', 'id': 'standard:date_time' }, +    { 'iconName': 'standard:decision', 'id': 'standard:decision' }, +    { 'iconName': 'standard:default', 'id': 'standard:default' }, +    { 'iconName': 'standard:delegated_account', 'id': 'standard:delegated_account' }, +    { 'iconName': 'standard:device', 'id': 'standard:device' }, +    { 'iconName': 'standard:display_rich_text', 'id': 'standard:display_rich_text' }, +    { 'iconName': 'standard:display_text', 'id': 'standard:display_text' }, +    { 'iconName': 'standard:document', 'id': 'standard:document' }, +    { 'iconName': 'standard:document_reference', 'id': 'standard:document_reference' }, +    { 'iconName': 'standard:drafts', 'id': 'standard:drafts' }, +    { 'iconName': 'standard:duration_downscale', 'id': 'standard:duration_downscale' }, +    { 'iconName': 'standard:dynamic_record_choice', 'id': 'standard:dynamic_record_choice' }, +    { 'iconName': 'standard:education', 'id': 'standard:education' }, +    { 'iconName': 'standard:einstein_replies', 'id': 'standard:einstein_replies' }, +    { 'iconName': 'standard:email', 'id': 'standard:email' }, +    { 'iconName': 'standard:email_chatter', 'id': 'standard:email_chatter' }, +    { 'iconName': 'standard:employee', 'id': 'standard:employee' }, +    { 'iconName': 'standard:employee_asset', 'id': 'standard:employee_asset' }, +    { 'iconName': 'standard:employee_contact', 'id': 'standard:employee_contact' }, +    { 'iconName': 'standard:employee_job', 'id': 'standard:employee_job' }, +    { 'iconName': 'standard:employee_job_position', 'id': 'standard:employee_job_position' }, +    { 'iconName': 'standard:employee_organization', 'id': 'standard:employee_organization' }, +    { 'iconName': 'standard:empty', 'id': 'standard:empty' }, +    { 'iconName': 'standard:endorsement', 'id': 'standard:endorsement' }, +    { 'iconName': 'standard:entitlement', 'id': 'standard:entitlement' }, +    { 'iconName': 'standard:entitlement_policy', 'id': 'standard:entitlement_policy' }, +    { 'iconName': 'standard:entitlement_process', 'id': 'standard:entitlement_process' }, +    { 'iconName': 'standard:entitlement_template', 'id': 'standard:entitlement_template' }, +    { 'iconName': 'standard:entity', 'id': 'standard:entity' }, +    { 'iconName': 'standard:entity_milestone', 'id': 'standard:entity_milestone' }, +    { 'iconName': 'standard:environment_hub', 'id': 'standard:environment_hub' }, +    { 'iconName': 'standard:event', 'id': 'standard:event' }, +    { 'iconName': 'standard:events', 'id': 'standard:events' }, +    { 'iconName': 'standard:expense', 'id': 'standard:expense' }, +    { 'iconName': 'standard:expense_report', 'id': 'standard:expense_report' }, +    { 'iconName': 'standard:expense_report_entry', 'id': 'standard:expense_report_entry' }, +    { 'iconName': 'standard:feed', 'id': 'standard:feed' }, +    { 'iconName': 'standard:feedback', 'id': 'standard:feedback' }, +    { 'iconName': 'standard:file', 'id': 'standard:file' }, +    { 'iconName': 'standard:filter', 'id': 'standard:filter' }, +    { 'iconName': 'standard:filter_criteria', 'id': 'standard:filter_criteria' }, +    { 'iconName': 'standard:filter_criteria_rule', 'id': 'standard:filter_criteria_rule' }, +    { 'iconName': 'standard:first_non_empty', 'id': 'standard:first_non_empty' }, +    { 'iconName': 'standard:flow', 'id': 'standard:flow' }, +    { 'iconName': 'standard:folder', 'id': 'standard:folder' }, +    { 'iconName': 'standard:forecasts', 'id': 'standard:forecasts' }, +    { 'iconName': 'standard:form', 'id': 'standard:form' }, +    { 'iconName': 'standard:formula', 'id': 'standard:formula' }, +    { 'iconName': 'standard:fulfillment_order', 'id': 'standard:fulfillment_order' }, +    { 'iconName': 'standard:generic_loading', 'id': 'standard:generic_loading' }, +    { 'iconName': 'standard:global_constant', 'id': 'standard:global_constant' }, +    { 'iconName': 'standard:goals', 'id': 'standard:goals' }, +    { 'iconName': 'standard:group_loading', 'id': 'standard:group_loading' }, +    { 'iconName': 'standard:groups', 'id': 'standard:groups' }, +    { 'iconName': 'standard:guidance_center', 'id': 'standard:guidance_center' }, +    { 'iconName': 'standard:hierarchy', 'id': 'standard:hierarchy' }, +    { 'iconName': 'standard:high_velocity_sales', 'id': 'standard:high_velocity_sales' }, +    { 'iconName': 'standard:holiday_operating_hours', 'id': 'standard:holiday_operating_hours' }, +    { 'iconName': 'standard:home', 'id': 'standard:home' }, +    { 'iconName': 'standard:household', 'id': 'standard:household' }, +    { 'iconName': 'standard:immunization', 'id': 'standard:immunization' }, +    { 'iconName': 'standard:individual', 'id': 'standard:individual' }, +    { 'iconName': 'standard:insights', 'id': 'standard:insights' }, +    { 'iconName': 'standard:instore_locations', 'id': 'standard:instore_locations' }, +    { 'iconName': 'standard:investment_account', 'id': 'standard:investment_account' }, +    { 'iconName': 'standard:invocable_action', 'id': 'standard:invocable_action' }, +    { 'iconName': 'standard:iot_context', 'id': 'standard:iot_context' }, +    { 'iconName': 'standard:iot_orchestrations', 'id': 'standard:iot_orchestrations' }, +    { 'iconName': 'standard:javascript_button', 'id': 'standard:javascript_button' }, +    { 'iconName': 'standard:job_family', 'id': 'standard:job_family' }, +    { 'iconName': 'standard:job_position', 'id': 'standard:job_position' }, +    { 'iconName': 'standard:job_profile', 'id': 'standard:job_profile' }, +    { 'iconName': 'standard:kanban', 'id': 'standard:kanban' }, +    { 'iconName': 'standard:key_dates', 'id': 'standard:key_dates' }, +    { 'iconName': 'standard:knowledge', 'id': 'standard:knowledge' }, +    { 'iconName': 'standard:lead', 'id': 'standard:lead' }, +    { 'iconName': 'standard:lead_insights', 'id': 'standard:lead_insights' }, +    { 'iconName': 'standard:lead_list', 'id': 'standard:lead_list' }, +    { 'iconName': 'standard:letterhead', 'id': 'standard:letterhead' }, +    { 'iconName': 'standard:lightning_component', 'id': 'standard:lightning_component' }, +    { 'iconName': 'standard:lightning_usage', 'id': 'standard:lightning_usage' }, +    { 'iconName': 'standard:link', 'id': 'standard:link' }, +    { 'iconName': 'standard:list_email', 'id': 'standard:list_email' }, +    { 'iconName': 'standard:live_chat', 'id': 'standard:live_chat' }, +    { 'iconName': 'standard:live_chat_visitor', 'id': 'standard:live_chat_visitor' }, +    { 'iconName': 'standard:location', 'id': 'standard:location' }, +    { 'iconName': 'standard:location_permit', 'id': 'standard:location_permit' }, +    { 'iconName': 'standard:log_a_call', 'id': 'standard:log_a_call' }, +    { 'iconName': 'standard:logging', 'id': 'standard:logging' }, +    { 'iconName': 'standard:loop', 'id': 'standard:loop' }, +    { 'iconName': 'standard:macros', 'id': 'standard:macros' }, +    { 'iconName': 'standard:maintenance_asset', 'id': 'standard:maintenance_asset' }, +    { 'iconName': 'standard:maintenance_plan', 'id': 'standard:maintenance_plan' }, +    { 'iconName': 'standard:maintenance_work_rule', 'id': 'standard:maintenance_work_rule' }, +    { 'iconName': 'standard:marketing_actions', 'id': 'standard:marketing_actions' }, +    { 'iconName': 'standard:medication_ingredient', 'id': 'standard:medication_ingredient' }, +    { 'iconName': 'standard:merge', 'id': 'standard:merge' }, +    { 'iconName': 'standard:messaging_conversation', 'id': 'standard:messaging_conversation' }, +    { 'iconName': 'standard:messaging_session', 'id': 'standard:messaging_session' }, +    { 'iconName': 'standard:messaging_user', 'id': 'standard:messaging_user' }, +    { 'iconName': 'standard:metrics', 'id': 'standard:metrics' }, +    { 'iconName': 'standard:multi_picklist', 'id': 'standard:multi_picklist' }, +    { 'iconName': 'standard:multi_select_checkbox', 'id': 'standard:multi_select_checkbox' }, +    { 'iconName': 'standard:news', 'id': 'standard:news' }, +    { 'iconName': 'standard:note', 'id': 'standard:note' }, +    { 'iconName': 'standard:number_input', 'id': 'standard:number_input' }, +    { 'iconName': 'standard:observation_component', 'id': 'standard:observation_component' }, +    { 'iconName': 'standard:omni_supervisor', 'id': 'standard:omni_supervisor' }, +    { 'iconName': 'standard:operating_hours', 'id': 'standard:operating_hours' }, +    { 'iconName': 'standard:opportunity', 'id': 'standard:opportunity' }, +    { 'iconName': 'standard:opportunity_contact_role', 'id': 'standard:opportunity_contact_role' }, +    { 'iconName': 'standard:opportunity_splits', 'id': 'standard:opportunity_splits' }, +    { 'iconName': 'standard:orchestrator', 'id': 'standard:orchestrator' }, +    { 'iconName': 'standard:order_item', 'id': 'standard:order_item' }, +    { 'iconName': 'standard:orders', 'id': 'standard:orders' }, +    { 'iconName': 'standard:outcome', 'id': 'standard:outcome' }, +    { 'iconName': 'standard:output', 'id': 'standard:output' }, +    { 'iconName': 'standard:partner_fund_allocation', 'id': 'standard:partner_fund_allocation' }, +    { 'iconName': 'standard:partner_fund_claim', 'id': 'standard:partner_fund_claim' }, +    { 'iconName': 'standard:partner_fund_request', 'id': 'standard:partner_fund_request' }, +    { 'iconName': 'standard:partner_marketing_budget', 'id': 'standard:partner_marketing_budget' }, +    { 'iconName': 'standard:partners', 'id': 'standard:partners' }, +    { 'iconName': 'standard:password', 'id': 'standard:password' }, +    { 'iconName': 'standard:past_chat', 'id': 'standard:past_chat' }, +    { 'iconName': 'standard:payment_gateway', 'id': 'standard:payment_gateway' }, +    { 'iconName': 'standard:people', 'id': 'standard:people' }, +    { 'iconName': 'standard:performance', 'id': 'standard:performance' }, +    { 'iconName': 'standard:person_account', 'id': 'standard:person_account' }, +    { 'iconName': 'standard:photo', 'id': 'standard:photo' }, +    { 'iconName': 'standard:picklist_choice', 'id': 'standard:picklist_choice' }, +    { 'iconName': 'standard:picklist_type', 'id': 'standard:picklist_type' }, +    { 'iconName': 'standard:planogram', 'id': 'standard:planogram' }, +    { 'iconName': 'standard:poll', 'id': 'standard:poll' }, +    { 'iconName': 'standard:portal', 'id': 'standard:portal' }, +    { 'iconName': 'standard:portal_roles', 'id': 'standard:portal_roles' }, +    { 'iconName': 'standard:portal_roles_and_subordinates', 'id': 'standard:portal_roles_and_subordinates' }, +    { 'iconName': 'standard:post', 'id': 'standard:post' }, +    { 'iconName': 'standard:practitioner_role', 'id': 'standard:practitioner_role' }, +    { 'iconName': 'standard:price_book_entries', 'id': 'standard:price_book_entries' }, +    { 'iconName': 'standard:price_books', 'id': 'standard:price_books' }, +    { 'iconName': 'standard:pricebook', 'id': 'standard:pricebook' }, +    { 'iconName': 'standard:pricing_workspace', 'id': 'standard:pricing_workspace' }, +    { 'iconName': 'standard:procedure', 'id': 'standard:procedure' }, +    { 'iconName': 'standard:procedure_detail', 'id': 'standard:procedure_detail' }, +    { 'iconName': 'standard:process', 'id': 'standard:process' }, +    { 'iconName': 'standard:process_exception', 'id': 'standard:process_exception' }, +    { 'iconName': 'standard:product', 'id': 'standard:product' }, +    { 'iconName': 'standard:product_consumed', 'id': 'standard:product_consumed' }, +    { 'iconName': 'standard:product_item', 'id': 'standard:product_item' }, +    { 'iconName': 'standard:product_item_transaction', 'id': 'standard:product_item_transaction' }, +    { 'iconName': 'standard:product_quantity_rules', 'id': 'standard:product_quantity_rules' }, +    { 'iconName': 'standard:product_request', 'id': 'standard:product_request' }, +    { 'iconName': 'standard:product_request_line_item', 'id': 'standard:product_request_line_item' }, +    { 'iconName': 'standard:product_required', 'id': 'standard:product_required' }, +    { 'iconName': 'standard:product_service_campaign', 'id': 'standard:product_service_campaign' }, +    { 'iconName': 'standard:product_service_campaign_item', 'id': 'standard:product_service_campaign_item' }, +    { 'iconName': 'standard:product_transfer', 'id': 'standard:product_transfer' }, +    { 'iconName': 'standard:product_warranty_term', 'id': 'standard:product_warranty_term' }, +    { 'iconName': 'standard:product_workspace', 'id': 'standard:product_workspace' }, +    { 'iconName': 'standard:products', 'id': 'standard:products' }, +    { 'iconName': 'standard:promotions', 'id': 'standard:promotions' }, +    { 'iconName': 'standard:propagation_policy', 'id': 'standard:propagation_policy' }, +    { 'iconName': 'standard:proposition', 'id': 'standard:proposition' }, +    { 'iconName': 'standard:question_best', 'id': 'standard:question_best' }, +    { 'iconName': 'standard:question_feed', 'id': 'standard:question_feed' }, +    { 'iconName': 'standard:queue', 'id': 'standard:queue' }, +    { 'iconName': 'standard:quick_text', 'id': 'standard:quick_text' }, +    { 'iconName': 'standard:quip', 'id': 'standard:quip' }, +    { 'iconName': 'standard:quip_sheet', 'id': 'standard:quip_sheet' }, +    { 'iconName': 'standard:quotes', 'id': 'standard:quotes' }, +    { 'iconName': 'standard:radio_button', 'id': 'standard:radio_button' }, +    { 'iconName': 'standard:read_receipts', 'id': 'standard:read_receipts' }, +    { 'iconName': 'standard:recent', 'id': 'standard:recent' }, +    { 'iconName': 'standard:recipe', 'id': 'standard:recipe' }, +    { 'iconName': 'standard:record', 'id': 'standard:record' }, +    { 'iconName': 'standard:record_create', 'id': 'standard:record_create' }, +    { 'iconName': 'standard:record_delete', 'id': 'standard:record_delete' }, +    { 'iconName': 'standard:record_lookup', 'id': 'standard:record_lookup' }, +    { 'iconName': 'standard:record_signature_task', 'id': 'standard:record_signature_task' }, +    { 'iconName': 'standard:record_update', 'id': 'standard:record_update' }, +    { 'iconName': 'standard:recycle_bin', 'id': 'standard:recycle_bin' }, +    { 'iconName': 'standard:related_list', 'id': 'standard:related_list' }, +    { 'iconName': 'standard:relationship', 'id': 'standard:relationship' }, +    { 'iconName': 'standard:reply_text', 'id': 'standard:reply_text' }, +    { 'iconName': 'standard:report', 'id': 'standard:report' }, +    { 'iconName': 'standard:resource_absence', 'id': 'standard:resource_absence' }, +    { 'iconName': 'standard:resource_capacity', 'id': 'standard:resource_capacity' }, +    { 'iconName': 'standard:resource_preference', 'id': 'standard:resource_preference' }, +    { 'iconName': 'standard:resource_skill', 'id': 'standard:resource_skill' }, +    { 'iconName': 'standard:restriction_policy', 'id': 'standard:restriction_policy' }, +    { 'iconName': 'standard:return_order', 'id': 'standard:return_order' }, +    { 'iconName': 'standard:return_order_line_item', 'id': 'standard:return_order_line_item' }, +    { 'iconName': 'standard:reward', 'id': 'standard:reward' }, +    { 'iconName': 'standard:rtc_presence', 'id': 'standard:rtc_presence' }, +    { 'iconName': 'standard:sales_cadence', 'id': 'standard:sales_cadence' }, +    { 'iconName': 'standard:sales_cadence_target', 'id': 'standard:sales_cadence_target' }, +    { 'iconName': 'standard:sales_channel', 'id': 'standard:sales_channel' }, +    { 'iconName': 'standard:sales_path', 'id': 'standard:sales_path' }, +    { 'iconName': 'standard:sales_value', 'id': 'standard:sales_value' }, +    { 'iconName': 'standard:salesforce_cms', 'id': 'standard:salesforce_cms' }, +    { 'iconName': 'standard:scan_card', 'id': 'standard:scan_card' }, +    { 'iconName': 'standard:schedule_objective', 'id': 'standard:schedule_objective' }, +    { 'iconName': 'standard:scheduling_constraint', 'id': 'standard:scheduling_constraint' }, +    { 'iconName': 'standard:scheduling_policy', 'id': 'standard:scheduling_policy' }, +    { 'iconName': 'standard:screen', 'id': 'standard:screen' }, +    { 'iconName': 'standard:search', 'id': 'standard:search' }, +    { 'iconName': 'standard:section', 'id': 'standard:section' }, +    { 'iconName': 'standard:segments', 'id': 'standard:segments' }, +    { 'iconName': 'standard:selling_model', 'id': 'standard:selling_model' }, +    { 'iconName': 'standard:serialized_product', 'id': 'standard:serialized_product' }, +    { 'iconName': 'standard:serialized_product_transaction', 'id': 'standard:serialized_product_transaction' }, +    { 'iconName': 'standard:service_appointment', 'id': 'standard:service_appointment' }, +    { 'iconName': 'standard:service_appointment_capacity_usage', 'id': 'standard:service_appointment_capacity_usage' }, +    { 'iconName': 'standard:service_contract', 'id': 'standard:service_contract' }, +    { 'iconName': 'standard:service_crew', 'id': 'standard:service_crew' }, +    { 'iconName': 'standard:service_crew_member', 'id': 'standard:service_crew_member' }, +    { 'iconName': 'standard:service_report', 'id': 'standard:service_report' }, +    { 'iconName': 'standard:service_request', 'id': 'standard:service_request' }, +    { 'iconName': 'standard:service_request_detail', 'id': 'standard:service_request_detail' }, +    { 'iconName': 'standard:service_resource', 'id': 'standard:service_resource' }, +    { 'iconName': 'standard:service_territory', 'id': 'standard:service_territory' }, +    { 'iconName': 'standard:service_territory_location', 'id': 'standard:service_territory_location' }, +    { 'iconName': 'standard:service_territory_member', 'id': 'standard:service_territory_member' }, +    { 'iconName': 'standard:service_territory_policy', 'id': 'standard:service_territory_policy' }, +    { 'iconName': 'standard:settings', 'id': 'standard:settings' }, +    { 'iconName': 'standard:shift', 'id': 'standard:shift' }, +    { 'iconName': 'standard:shift_pattern', 'id': 'standard:shift_pattern' }, +    { 'iconName': 'standard:shift_pattern_entry', 'id': 'standard:shift_pattern_entry' }, +    { 'iconName': 'standard:shift_preference', 'id': 'standard:shift_preference' }, +    { 'iconName': 'standard:shift_scheduling_operation', 'id': 'standard:shift_scheduling_operation' }, +    { 'iconName': 'standard:shift_template', 'id': 'standard:shift_template' }, +    { 'iconName': 'standard:shift_type', 'id': 'standard:shift_type' }, +    { 'iconName': 'standard:shipment', 'id': 'standard:shipment' }, +    { 'iconName': 'standard:skill', 'id': 'standard:skill' }, +    { 'iconName': 'standard:skill_entity', 'id': 'standard:skill_entity' }, +    { 'iconName': 'standard:skill_requirement', 'id': 'standard:skill_requirement' }, +    { 'iconName': 'standard:slider', 'id': 'standard:slider' }, +    { 'iconName': 'standard:sms', 'id': 'standard:sms' }, +    { 'iconName': 'standard:snippet', 'id': 'standard:snippet' }, +    { 'iconName': 'standard:snippets', 'id': 'standard:snippets' }, +    { 'iconName': 'standard:sobject', 'id': 'standard:sobject' }, +    { 'iconName': 'standard:sobject_collection', 'id': 'standard:sobject_collection' }, +    { 'iconName': 'standard:social', 'id': 'standard:social' }, +    { 'iconName': 'standard:solution', 'id': 'standard:solution' }, +    { 'iconName': 'standard:sort', 'id': 'standard:sort' }, +    { 'iconName': 'standard:sort_policy', 'id': 'standard:sort_policy' }, +    { 'iconName': 'standard:sossession', 'id': 'standard:sossession' }, +    { 'iconName': 'standard:stage', 'id': 'standard:stage' }, +    { 'iconName': 'standard:stage_collection', 'id': 'standard:stage_collection' }, +    { 'iconName': 'standard:steps', 'id': 'standard:steps' }, +    { 'iconName': 'standard:store', 'id': 'standard:store' }, +    { 'iconName': 'standard:store_group', 'id': 'standard:store_group' }, +    { 'iconName': 'standard:story', 'id': 'standard:story' }, +    { 'iconName': 'standard:strategy', 'id': 'standard:strategy' }, +    { 'iconName': 'standard:survey', 'id': 'standard:survey' }, +    { 'iconName': 'standard:swarm_request', 'id': 'standard:swarm_request' }, +    { 'iconName': 'standard:swarm_session', 'id': 'standard:swarm_session' }, +    { 'iconName': 'standard:system_and_global_variable', 'id': 'standard:system_and_global_variable' }, +    { 'iconName': 'standard:task', 'id': 'standard:task' }, +    { 'iconName': 'standard:task2', 'id': 'standard:task2' }, +    { 'iconName': 'standard:team_member', 'id': 'standard:team_member' }, +    { 'iconName': 'standard:template', 'id': 'standard:template' }, +    { 'iconName': 'standard:text', 'id': 'standard:text' }, +    { 'iconName': 'standard:text_template', 'id': 'standard:text_template' }, +    { 'iconName': 'standard:textarea', 'id': 'standard:textarea' }, +    { 'iconName': 'standard:textbox', 'id': 'standard:textbox' }, +    { 'iconName': 'standard:thanks', 'id': 'standard:thanks' }, +    { 'iconName': 'standard:thanks_loading', 'id': 'standard:thanks_loading' }, +    { 'iconName': 'standard:timesheet', 'id': 'standard:timesheet' }, +    { 'iconName': 'standard:timesheet_entry', 'id': 'standard:timesheet_entry' }, +    { 'iconName': 'standard:timeslot', 'id': 'standard:timeslot' }, +    { 'iconName': 'standard:today', 'id': 'standard:today' }, +    { 'iconName': 'standard:toggle', 'id': 'standard:toggle' }, +    { 'iconName': 'standard:topic', 'id': 'standard:topic' }, +    { 'iconName': 'standard:topic2', 'id': 'standard:topic2' }, +    { 'iconName': 'standard:trailhead', 'id': 'standard:trailhead' }, +    { 'iconName': 'standard:trailhead_alt', 'id': 'standard:trailhead_alt' }, +    { 'iconName': 'standard:travel_mode', 'id': 'standard:travel_mode' }, +    { 'iconName': 'standard:unmatched', 'id': 'standard:unmatched' }, +    { 'iconName': 'standard:user', 'id': 'standard:user' }, +    { 'iconName': 'standard:user_role', 'id': 'standard:user_role' }, +    { 'iconName': 'standard:variable', 'id': 'standard:variable' }, +    { 'iconName': 'standard:variation_attribute_setup', 'id': 'standard:variation_attribute_setup' }, +    { 'iconName': 'standard:variation_products', 'id': 'standard:variation_products' }, +    { 'iconName': 'standard:video', 'id': 'standard:video' }, +    { 'iconName': 'standard:visit_templates', 'id': 'standard:visit_templates' }, +    { 'iconName': 'standard:visits', 'id': 'standard:visits' }, +    { 'iconName': 'standard:visualforce_page', 'id': 'standard:visualforce_page' }, +    { 'iconName': 'standard:voice_call', 'id': 'standard:voice_call' }, +    { 'iconName': 'standard:waits', 'id': 'standard:waits' }, +    { 'iconName': 'standard:warranty_term', 'id': 'standard:warranty_term' }, +    { 'iconName': 'standard:webcart', 'id': 'standard:webcart' }, +    { 'iconName': 'standard:work_capacity_limit', 'id': 'standard:work_capacity_limit' }, +    { 'iconName': 'standard:work_capacity_usage', 'id': 'standard:work_capacity_usage' }, +    { 'iconName': 'standard:work_contract', 'id': 'standard:work_contract' }, +    { 'iconName': 'standard:work_forecast', 'id': 'standard:work_forecast' }, +    { 'iconName': 'standard:work_order', 'id': 'standard:work_order' }, +    { 'iconName': 'standard:work_order_item', 'id': 'standard:work_order_item' }, +    { 'iconName': 'standard:work_plan', 'id': 'standard:work_plan' }, +    { 'iconName': 'standard:work_plan_rule', 'id': 'standard:work_plan_rule' }, +    { 'iconName': 'standard:work_plan_template', 'id': 'standard:work_plan_template' }, +    { 'iconName': 'standard:work_plan_template_entry', 'id': 'standard:work_plan_template_entry' }, +    { 'iconName': 'standard:work_queue', 'id': 'standard:work_queue' }, +    { 'iconName': 'standard:work_step', 'id': 'standard:work_step' }, +    { 'iconName': 'standard:work_step_template', 'id': 'standard:work_step_template' }, +    { 'iconName': 'standard:work_type', 'id': 'standard:work_type' }, +    { 'iconName': 'standard:work_type_group', 'id': 'standard:work_type_group' } +] + +const UTILITY_ICONS = [ + { 'iconName': 'utility:activity', 'id': 'utility:activity' }, + { 'iconName': 'utility:ad_set', 'id': 'utility:ad_set' }, + { 'iconName': 'utility:add', 'id': 'utility:add' }, + { 'iconName': 'utility:adduser', 'id': 'utility:adduser' }, + { 'iconName': 'utility:adjust_value', 'id': 'utility:adjust_value' }, + { 'iconName': 'utility:advanced_function', 'id': 'utility:advanced_function' }, + { 'iconName': 'utility:advertising', 'id': 'utility:advertising' }, + { 'iconName': 'utility:agent_home', 'id': 'utility:agent_home' }, + { 'iconName': 'utility:agent_session', 'id': 'utility:agent_session' }, + { 'iconName': 'utility:aggregation_policy', 'id': 'utility:aggregation_policy' }, + { 'iconName': 'utility:alert', 'id': 'utility:alert' }, + { 'iconName': 'utility:all', 'id': 'utility:all' }, + { 'iconName': 'utility:anchor', 'id': 'utility:anchor' }, + { 'iconName': 'utility:animal_and_nature', 'id': 'utility:animal_and_nature' }, + { 'iconName': 'utility:announcement', 'id': 'utility:announcement' }, + { 'iconName': 'utility:answer', 'id': 'utility:answer' }, + { 'iconName': 'utility:answered_twice', 'id': 'utility:answered_twice' }, + { 'iconName': 'utility:anywhere_alert', 'id': 'utility:anywhere_alert' }, + { 'iconName': 'utility:anywhere_chat', 'id': 'utility:anywhere_chat' }, + { 'iconName': 'utility:apex', 'id': 'utility:apex' }, + { 'iconName': 'utility:apex_plugin', 'id': 'utility:apex_plugin' }, + { 'iconName': 'utility:approval', 'id': 'utility:approval' }, + { 'iconName': 'utility:apps', 'id': 'utility:apps' }, + { 'iconName': 'utility:archive', 'id': 'utility:archive' }, + { 'iconName': 'utility:arrow_bottom', 'id': 'utility:arrow_bottom' }, + { 'iconName': 'utility:arrow_left', 'id': 'utility:arrow_left' }, + { 'iconName': 'utility:arrow_right', 'id': 'utility:arrow_right' }, + { 'iconName': 'utility:arrow_top', 'id': 'utility:arrow_top' }, + { 'iconName': 'utility:arrowdown', 'id': 'utility:arrowdown' }, + { 'iconName': 'utility:arrowup', 'id': 'utility:arrowup' }, + { 'iconName': 'utility:asset_warranty', 'id': 'utility:asset_warranty' }, + { 'iconName': 'utility:assignment', 'id': 'utility:assignment' }, + { 'iconName': 'utility:attach', 'id': 'utility:attach' }, + { 'iconName': 'utility:automate', 'id': 'utility:automate' }, + { 'iconName': 'utility:away', 'id': 'utility:away' }, + { 'iconName': 'utility:back', 'id': 'utility:back' }, + { 'iconName': 'utility:ban', 'id': 'utility:ban' }, + { 'iconName': 'utility:block_visitor', 'id': 'utility:block_visitor' }, + { 'iconName': 'utility:bold', 'id': 'utility:bold' }, + { 'iconName': 'utility:bookmark', 'id': 'utility:bookmark' }, + { 'iconName': 'utility:bottom_align', 'id': 'utility:bottom_align' }, + { 'iconName': 'utility:breadcrumbs', 'id': 'utility:breadcrumbs' }, + { 'iconName': 'utility:broadcast', 'id': 'utility:broadcast' }, + { 'iconName': 'utility:brush', 'id': 'utility:brush' }, + { 'iconName': 'utility:bucket', 'id': 'utility:bucket' }, + { 'iconName': 'utility:bug', 'id': 'utility:bug' }, + { 'iconName': 'utility:builder', 'id': 'utility:builder' }, + { 'iconName': 'utility:bundle_config', 'id': 'utility:bundle_config' }, + { 'iconName': 'utility:bundle_policy', 'id': 'utility:bundle_policy' }, + { 'iconName': 'utility:button_choice', 'id': 'utility:button_choice' }, + { 'iconName': 'utility:calculated_insights', 'id': 'utility:calculated_insights' }, + { 'iconName': 'utility:call', 'id': 'utility:call' }, + { 'iconName': 'utility:campaign', 'id': 'utility:campaign' }, + { 'iconName': 'utility:cancel_file_request', 'id': 'utility:cancel_file_request' }, + { 'iconName': 'utility:cancel_transfer', 'id': 'utility:cancel_transfer' }, + { 'iconName': 'utility:capacity_plan', 'id': 'utility:capacity_plan' }, + { 'iconName': 'utility:capslock', 'id': 'utility:capslock' }, + { 'iconName': 'utility:cart', 'id': 'utility:cart' }, + { 'iconName': 'utility:case', 'id': 'utility:case' }, + { 'iconName': 'utility:cases', 'id': 'utility:cases' }, + { 'iconName': 'utility:center_align', 'id': 'utility:center_align' }, + { 'iconName': 'utility:center_align_text', 'id': 'utility:center_align_text' }, + { 'iconName': 'utility:change_owner', 'id': 'utility:change_owner' }, + { 'iconName': 'utility:change_record_type', 'id': 'utility:change_record_type' }, + { 'iconName': 'utility:chart', 'id': 'utility:chart' }, + { 'iconName': 'utility:chat', 'id': 'utility:chat' }, + { 'iconName': 'utility:check', 'id': 'utility:check' }, + { 'iconName': 'utility:checkin', 'id': 'utility:checkin' }, + { 'iconName': 'utility:checkout', 'id': 'utility:checkout' }, + { 'iconName': 'utility:chevrondown', 'id': 'utility:chevrondown' }, + { 'iconName': 'utility:chevronleft', 'id': 'utility:chevronleft' }, + { 'iconName': 'utility:chevronright', 'id': 'utility:chevronright' }, + { 'iconName': 'utility:chevronup', 'id': 'utility:chevronup' }, + { 'iconName': 'utility:choice', 'id': 'utility:choice' }, + { 'iconName': 'utility:classic_interface', 'id': 'utility:classic_interface' }, + { 'iconName': 'utility:clear', 'id': 'utility:clear' }, + { 'iconName': 'utility:clock', 'id': 'utility:clock' }, + { 'iconName': 'utility:close', 'id': 'utility:close' }, + { 'iconName': 'utility:collapse_all', 'id': 'utility:collapse_all' }, + { 'iconName': 'utility:collection', 'id': 'utility:collection' }, + { 'iconName': 'utility:collection_variable', 'id': 'utility:collection_variable' }, + { 'iconName': 'utility:color_swatch', 'id': 'utility:color_swatch' }, + { 'iconName': 'utility:comments', 'id': 'utility:comments' }, + { 'iconName': 'utility:company', 'id': 'utility:company' }, + { 'iconName': 'utility:component_customization', 'id': 'utility:component_customization' }, + { 'iconName': 'utility:connected_apps', 'id': 'utility:connected_apps' }, + { 'iconName': 'utility:constant', 'id': 'utility:constant' }, + { 'iconName': 'utility:contact_request', 'id': 'utility:contact_request' }, + { 'iconName': 'utility:contract', 'id': 'utility:contract' }, + { 'iconName': 'utility:contract_alt', 'id': 'utility:contract_alt' }, + { 'iconName': 'utility:copy', 'id': 'utility:copy' }, + { 'iconName': 'utility:copy_to_clipboard', 'id': 'utility:copy_to_clipboard' }, + { 'iconName': 'utility:crossfilter', 'id': 'utility:crossfilter' }, + { 'iconName': 'utility:currency', 'id': 'utility:currency' }, + { 'iconName': 'utility:currency_input', 'id': 'utility:currency_input' }, + { 'iconName': 'utility:custom_apps', 'id': 'utility:custom_apps' }, + { 'iconName': 'utility:cut', 'id': 'utility:cut' }, + { 'iconName': 'utility:dash', 'id': 'utility:dash' }, + { 'iconName': 'utility:data_mapping', 'id': 'utility:data_mapping' }, + { 'iconName': 'utility:database', 'id': 'utility:database' }, + { 'iconName': 'utility:datadotcom', 'id': 'utility:datadotcom' }, + { 'iconName': 'utility:date_input', 'id': 'utility:date_input' }, + { 'iconName': 'utility:date_time', 'id': 'utility:date_time' }, + { 'iconName': 'utility:dayview', 'id': 'utility:dayview' }, + { 'iconName': 'utility:delete', 'id': 'utility:delete' }, + { 'iconName': 'utility:deprecate', 'id': 'utility:deprecate' }, + { 'iconName': 'utility:description', 'id': 'utility:description' }, + { 'iconName': 'utility:desktop', 'id': 'utility:desktop' }, + { 'iconName': 'utility:desktop_and_phone', 'id': 'utility:desktop_and_phone' }, + { 'iconName': 'utility:desktop_console', 'id': 'utility:desktop_console' }, + { 'iconName': 'utility:dialing', 'id': 'utility:dialing' }, + { 'iconName': 'utility:diamond', 'id': 'utility:diamond' }, + { 'iconName': 'utility:dislike', 'id': 'utility:dislike' }, + { 'iconName': 'utility:display_rich_text', 'id': 'utility:display_rich_text' }, + { 'iconName': 'utility:display_text', 'id': 'utility:display_text' }, + { 'iconName': 'utility:dock_panel', 'id': 'utility:dock_panel' }, + { 'iconName': 'utility:down', 'id': 'utility:down' }, + { 'iconName': 'utility:download', 'id': 'utility:download' }, + { 'iconName': 'utility:drag', 'id': 'utility:drag' }, + { 'iconName': 'utility:drag_and_drop', 'id': 'utility:drag_and_drop' }, + { 'iconName': 'utility:duration_downscale', 'id': 'utility:duration_downscale' }, + { 'iconName': 'utility:dynamic_record_choice', 'id': 'utility:dynamic_record_choice' }, + { 'iconName': 'utility:edit', 'id': 'utility:edit' }, + { 'iconName': 'utility:edit_form', 'id': 'utility:edit_form' }, + { 'iconName': 'utility:education', 'id': 'utility:education' }, + { 'iconName': 'utility:einstein', 'id': 'utility:einstein' }, + { 'iconName': 'utility:email', 'id': 'utility:email' }, + { 'iconName': 'utility:email_open', 'id': 'utility:email_open' }, + { 'iconName': 'utility:emoji', 'id': 'utility:emoji' }, + { 'iconName': 'utility:end_call', 'id': 'utility:end_call' }, + { 'iconName': 'utility:end_chat', 'id': 'utility:end_chat' }, + { 'iconName': 'utility:end_messaging_session', 'id': 'utility:end_messaging_session' }, + { 'iconName': 'utility:engage', 'id': 'utility:engage' }, + { 'iconName': 'utility:enter', 'id': 'utility:enter' }, + { 'iconName': 'utility:erect_window', 'id': 'utility:erect_window' }, + { 'iconName': 'utility:error', 'id': 'utility:error' }, + { 'iconName': 'utility:event', 'id': 'utility:event' }, + { 'iconName': 'utility:event_ext', 'id': 'utility:event_ext' }, + { 'iconName': 'utility:events', 'id': 'utility:events' }, + { 'iconName': 'utility:expand', 'id': 'utility:expand' }, + { 'iconName': 'utility:expand_all', 'id': 'utility:expand_all' }, + { 'iconName': 'utility:expand_alt', 'id': 'utility:expand_alt' }, + { 'iconName': 'utility:fallback', 'id': 'utility:fallback' }, + { 'iconName': 'utility:favorite', 'id': 'utility:favorite' }, + { 'iconName': 'utility:feed', 'id': 'utility:feed' }, + { 'iconName': 'utility:file', 'id': 'utility:file' }, + { 'iconName': 'utility:filter', 'id': 'utility:filter' }, + { 'iconName': 'utility:filter_criteria', 'id': 'utility:filter_criteria' }, + { 'iconName': 'utility:filter_criteria_rule', 'id': 'utility:filter_criteria_rule' }, + { 'iconName': 'utility:filterList', 'id': 'utility:filterList' }, + { 'iconName': 'utility:flow', 'id': 'utility:flow' }, + { 'iconName': 'utility:flow_alt', 'id': 'utility:flow_alt' }, + { 'iconName': 'utility:food_and_drink', 'id': 'utility:food_and_drink' }, + { 'iconName': 'utility:form', 'id': 'utility:form' }, + { 'iconName': 'utility:formula', 'id': 'utility:formula' }, + { 'iconName': 'utility:forward', 'id': 'utility:forward' }, + { 'iconName': 'utility:forward_up', 'id': 'utility:forward_up' }, + { 'iconName': 'utility:freeze_column', 'id': 'utility:freeze_column' }, + { 'iconName': 'utility:frozen', 'id': 'utility:frozen' }, + { 'iconName': 'utility:fulfillment_order', 'id': 'utility:fulfillment_order' }, + { 'iconName': 'utility:full_width_view', 'id': 'utility:full_width_view' }, + { 'iconName': 'utility:global_constant', 'id': 'utility:global_constant' }, + { 'iconName': 'utility:graph', 'id': 'utility:graph' }, + { 'iconName': 'utility:groups', 'id': 'utility:groups' }, + { 'iconName': 'utility:help', 'id': 'utility:help' }, + { 'iconName': 'utility:help_center', 'id': 'utility:help_center' }, + { 'iconName': 'utility:help_doc_ext', 'id': 'utility:help_doc_ext' }, + { 'iconName': 'utility:hide', 'id': 'utility:hide' }, + { 'iconName': 'utility:hide_mobile', 'id': 'utility:hide_mobile' }, + { 'iconName': 'utility:hierarchy', 'id': 'utility:hierarchy' }, + { 'iconName': 'utility:high_velocity_sales', 'id': 'utility:high_velocity_sales' }, + { 'iconName': 'utility:holiday_operating_hours', 'id': 'utility:holiday_operating_hours' }, + { 'iconName': 'utility:home', 'id': 'utility:home' }, + { 'iconName': 'utility:identity', 'id': 'utility:identity' }, + { 'iconName': 'utility:image', 'id': 'utility:image' }, + { 'iconName': 'utility:in_app_assistant', 'id': 'utility:in_app_assistant' }, + { 'iconName': 'utility:inbox', 'id': 'utility:inbox' }, + { 'iconName': 'utility:incoming_call', 'id': 'utility:incoming_call' }, + { 'iconName': 'utility:info', 'id': 'utility:info' }, + { 'iconName': 'utility:info_alt', 'id': 'utility:info_alt' }, + { 'iconName': 'utility:insert_tag_field', 'id': 'utility:insert_tag_field' }, + { 'iconName': 'utility:insert_template', 'id': 'utility:insert_template' }, + { 'iconName': 'utility:inspector_panel', 'id': 'utility:inspector_panel' }, + { 'iconName': 'utility:internal_share', 'id': 'utility:internal_share' }, + { 'iconName': 'utility:italic', 'id': 'utility:italic' }, + { 'iconName': 'utility:jump_to_bottom', 'id': 'utility:jump_to_bottom' }, + { 'iconName': 'utility:jump_to_left', 'id': 'utility:jump_to_left' }, + { 'iconName': 'utility:jump_to_right', 'id': 'utility:jump_to_right' }, + { 'iconName': 'utility:jump_to_top', 'id': 'utility:jump_to_top' }, + { 'iconName': 'utility:justify_text', 'id': 'utility:justify_text' }, + { 'iconName': 'utility:kanban', 'id': 'utility:kanban' }, + { 'iconName': 'utility:key', 'id': 'utility:key' }, + { 'iconName': 'utility:key_dates', 'id': 'utility:key_dates' }, + { 'iconName': 'utility:keyboard_dismiss', 'id': 'utility:keyboard_dismiss' }, + { 'iconName': 'utility:keypad', 'id': 'utility:keypad' }, + { 'iconName': 'utility:knowledge_base', 'id': 'utility:knowledge_base' }, + { 'iconName': 'utility:layers', 'id': 'utility:layers' }, + { 'iconName': 'utility:layout', 'id': 'utility:layout' }, + { 'iconName': 'utility:leave_conference', 'id': 'utility:leave_conference' }, + { 'iconName': 'utility:left', 'id': 'utility:left' }, + { 'iconName': 'utility:left_align', 'id': 'utility:left_align' }, + { 'iconName': 'utility:left_align_text', 'id': 'utility:left_align_text' }, + { 'iconName': 'utility:level_down', 'id': 'utility:level_down' }, + { 'iconName': 'utility:level_up', 'id': 'utility:level_up' }, + { 'iconName': 'utility:light_bulb', 'id': 'utility:light_bulb' }, + { 'iconName': 'utility:lightning_extension', 'id': 'utility:lightning_extension' }, + { 'iconName': 'utility:lightning_inspector', 'id': 'utility:lightning_inspector' }, + { 'iconName': 'utility:like', 'id': 'utility:like' }, + { 'iconName': 'utility:link', 'id': 'utility:link' }, + { 'iconName': 'utility:linked', 'id': 'utility:linked' }, + { 'iconName': 'utility:list', 'id': 'utility:list' }, + { 'iconName': 'utility:listen', 'id': 'utility:listen' }, + { 'iconName': 'utility:live_message', 'id': 'utility:live_message' }, + { 'iconName': 'utility:location', 'id': 'utility:location' }, + { 'iconName': 'utility:location_permit', 'id': 'utility:location_permit' }, + { 'iconName': 'utility:lock', 'id': 'utility:lock' }, + { 'iconName': 'utility:locker_service_api_viewer', 'id': 'utility:locker_service_api_viewer' }, + { 'iconName': 'utility:locker_service_console', 'id': 'utility:locker_service_console' }, + { 'iconName': 'utility:log_a_call', 'id': 'utility:log_a_call' }, + { 'iconName': 'utility:logout', 'id': 'utility:logout' }, + { 'iconName': 'utility:loop', 'id': 'utility:loop' }, + { 'iconName': 'utility:lower_flag', 'id': 'utility:lower_flag' }, + { 'iconName': 'utility:macros', 'id': 'utility:macros' }, + { 'iconName': 'utility:magicwand', 'id': 'utility:magicwand' }, + { 'iconName': 'utility:mark_all_as_read', 'id': 'utility:mark_all_as_read' }, + { 'iconName': 'utility:matrix', 'id': 'utility:matrix' }, + { 'iconName': 'utility:meet_content_source', 'id': 'utility:meet_content_source' }, + { 'iconName': 'utility:meet_focus_content', 'id': 'utility:meet_focus_content' }, + { 'iconName': 'utility:meet_focus_equal', 'id': 'utility:meet_focus_equal' }, + { 'iconName': 'utility:meet_focus_presenter', 'id': 'utility:meet_focus_presenter' }, + { 'iconName': 'utility:meet_present_panel', 'id': 'utility:meet_present_panel' }, + { 'iconName': 'utility:merge', 'id': 'utility:merge' }, + { 'iconName': 'utility:merge_field', 'id': 'utility:merge_field' }, + { 'iconName': 'utility:metrics', 'id': 'utility:metrics' }, + { 'iconName': 'utility:middle_align', 'id': 'utility:middle_align' }, + { 'iconName': 'utility:minimize_window', 'id': 'utility:minimize_window' }, + { 'iconName': 'utility:missed_call', 'id': 'utility:missed_call' }, + { 'iconName': 'utility:money', 'id': 'utility:money' }, + { 'iconName': 'utility:moneybag', 'id': 'utility:moneybag' }, + { 'iconName': 'utility:monthlyview', 'id': 'utility:monthlyview' }, + { 'iconName': 'utility:move', 'id': 'utility:move' }, + { 'iconName': 'utility:multi_picklist', 'id': 'utility:multi_picklist' }, + { 'iconName': 'utility:multi_select_checkbox', 'id': 'utility:multi_select_checkbox' }, + { 'iconName': 'utility:muted', 'id': 'utility:muted' }, + { 'iconName': 'utility:new', 'id': 'utility:new' }, + { 'iconName': 'utility:new_direct_message', 'id': 'utility:new_direct_message' }, + { 'iconName': 'utility:new_window', 'id': 'utility:new_window' }, + { 'iconName': 'utility:news', 'id': 'utility:news' }, + { 'iconName': 'utility:note', 'id': 'utility:note' }, + { 'iconName': 'utility:notebook', 'id': 'utility:notebook' }, + { 'iconName': 'utility:notification', 'id': 'utility:notification' }, + { 'iconName': 'utility:number_input', 'id': 'utility:number_input' }, + { 'iconName': 'utility:office365', 'id': 'utility:office365' }, + { 'iconName': 'utility:offline', 'id': 'utility:offline' }, + { 'iconName': 'utility:offline_briefcase', 'id': 'utility:offline_briefcase' }, + { 'iconName': 'utility:offline_cached', 'id': 'utility:offline_cached' }, + { 'iconName': 'utility:omni_channel', 'id': 'utility:omni_channel' }, + { 'iconName': 'utility:open', 'id': 'utility:open' }, + { 'iconName': 'utility:open_folder', 'id': 'utility:open_folder' }, + { 'iconName': 'utility:opened_folder', 'id': 'utility:opened_folder' }, + { 'iconName': 'utility:orchestrator', 'id': 'utility:orchestrator' }, + { 'iconName': 'utility:org_chart', 'id': 'utility:org_chart' }, + { 'iconName': 'utility:outbound_call', 'id': 'utility:outbound_call' }, + { 'iconName': 'utility:outcome', 'id': 'utility:outcome' }, + { 'iconName': 'utility:overflow', 'id': 'utility:overflow' }, + { 'iconName': 'utility:package', 'id': 'utility:package' }, + { 'iconName': 'utility:package_org', 'id': 'utility:package_org' }, + { 'iconName': 'utility:package_org_beta', 'id': 'utility:package_org_beta' }, + { 'iconName': 'utility:page', 'id': 'utility:page' }, + { 'iconName': 'utility:palette', 'id': 'utility:palette' }, + { 'iconName': 'utility:password', 'id': 'utility:password' }, + { 'iconName': 'utility:paste', 'id': 'utility:paste' }, + { 'iconName': 'utility:pause', 'id': 'utility:pause' }, + { 'iconName': 'utility:pause_alt', 'id': 'utility:pause_alt' }, + { 'iconName': 'utility:payment_gateway', 'id': 'utility:payment_gateway' }, + { 'iconName': 'utility:pdf_ext', 'id': 'utility:pdf_ext' }, + { 'iconName': 'utility:people', 'id': 'utility:people' }, + { 'iconName': 'utility:percent', 'id': 'utility:percent' }, + { 'iconName': 'utility:phone_landscape', 'id': 'utility:phone_landscape' }, + { 'iconName': 'utility:phone_portrait', 'id': 'utility:phone_portrait' }, + { 'iconName': 'utility:photo', 'id': 'utility:photo' }, + { 'iconName': 'utility:picklist', 'id': 'utility:picklist' }, + { 'iconName': 'utility:picklist_choice', 'id': 'utility:picklist_choice' }, + { 'iconName': 'utility:picklist_type', 'id': 'utility:picklist_type' }, + { 'iconName': 'utility:pin', 'id': 'utility:pin' }, + { 'iconName': 'utility:pinned', 'id': 'utility:pinned' }, + { 'iconName': 'utility:planning_poker', 'id': 'utility:planning_poker' }, + { 'iconName': 'utility:play', 'id': 'utility:play' }, + { 'iconName': 'utility:podcast_webinar', 'id': 'utility:podcast_webinar' }, + { 'iconName': 'utility:pop_in', 'id': 'utility:pop_in' }, + { 'iconName': 'utility:power', 'id': 'utility:power' }, + { 'iconName': 'utility:preview', 'id': 'utility:preview' }, + { 'iconName': 'utility:price_book_entries', 'id': 'utility:price_book_entries' }, + { 'iconName': 'utility:price_books', 'id': 'utility:price_books' }, + { 'iconName': 'utility:pricing_workspace', 'id': 'utility:pricing_workspace' }, + { 'iconName': 'utility:print', 'id': 'utility:print' }, + { 'iconName': 'utility:priority', 'id': 'utility:priority' }, + { 'iconName': 'utility:privately_shared', 'id': 'utility:privately_shared' }, + { 'iconName': 'utility:process', 'id': 'utility:process' }, + { 'iconName': 'utility:product_quantity_rules', 'id': 'utility:product_quantity_rules' }, + { 'iconName': 'utility:product_service_campaign', 'id': 'utility:product_service_campaign' }, + { 'iconName': 'utility:product_service_campaign_item', 'id': 'utility:product_service_campaign_item' }, + { 'iconName': 'utility:product_warranty_term', 'id': 'utility:product_warranty_term' }, + { 'iconName': 'utility:product_workspace', 'id': 'utility:product_workspace' }, + { 'iconName': 'utility:products', 'id': 'utility:products' }, + { 'iconName': 'utility:profile', 'id': 'utility:profile' }, + { 'iconName': 'utility:promotions', 'id': 'utility:promotions' }, + { 'iconName': 'utility:prompt', 'id': 'utility:prompt' }, + { 'iconName': 'utility:prompt_edit', 'id': 'utility:prompt_edit' }, + { 'iconName': 'utility:propagation_policy', 'id': 'utility:propagation_policy' }, + { 'iconName': 'utility:push', 'id': 'utility:push' }, + { 'iconName': 'utility:puzzle', 'id': 'utility:puzzle' }, + { 'iconName': 'utility:question', 'id': 'utility:question' }, + { 'iconName': 'utility:question_mark', 'id': 'utility:question_mark' }, + { 'iconName': 'utility:questions_and_answers', 'id': 'utility:questions_and_answers' }, + { 'iconName': 'utility:quick_text', 'id': 'utility:quick_text' }, + { 'iconName': 'utility:quip', 'id': 'utility:quip' }, + { 'iconName': 'utility:quotation_marks', 'id': 'utility:quotation_marks' }, + { 'iconName': 'utility:quote', 'id': 'utility:quote' }, + { 'iconName': 'utility:radio_button', 'id': 'utility:radio_button' }, + { 'iconName': 'utility:rating', 'id': 'utility:rating' }, + { 'iconName': 'utility:reassign', 'id': 'utility:reassign' }, + { 'iconName': 'utility:recipe', 'id': 'utility:recipe' }, + { 'iconName': 'utility:record', 'id': 'utility:record' }, + { 'iconName': 'utility:record_create', 'id': 'utility:record_create' }, + { 'iconName': 'utility:record_delete', 'id': 'utility:record_delete' }, + { 'iconName': 'utility:record_lookup', 'id': 'utility:record_lookup' }, + { 'iconName': 'utility:record_update', 'id': 'utility:record_update' }, + { 'iconName': 'utility:recurring_exception', 'id': 'utility:recurring_exception' }, + { 'iconName': 'utility:recycle_bin_empty', 'id': 'utility:recycle_bin_empty' }, + { 'iconName': 'utility:recycle_bin_full', 'id': 'utility:recycle_bin_full' }, + { 'iconName': 'utility:redo', 'id': 'utility:redo' }, + { 'iconName': 'utility:refresh', 'id': 'utility:refresh' }, + { 'iconName': 'utility:relate', 'id': 'utility:relate' }, + { 'iconName': 'utility:reminder', 'id': 'utility:reminder' }, + { 'iconName': 'utility:remove_formatting', 'id': 'utility:remove_formatting' }, + { 'iconName': 'utility:remove_link', 'id': 'utility:remove_link' }, + { 'iconName': 'utility:replace', 'id': 'utility:replace' }, + { 'iconName': 'utility:reply', 'id': 'utility:reply' }, + { 'iconName': 'utility:reply_all', 'id': 'utility:reply_all' }, + { 'iconName': 'utility:report_issue', 'id': 'utility:report_issue' }, + { 'iconName': 'utility:reset_password', 'id': 'utility:reset_password' }, + { 'iconName': 'utility:resource_absence', 'id': 'utility:resource_absence' }, + { 'iconName': 'utility:resource_capacity', 'id': 'utility:resource_capacity' }, + { 'iconName': 'utility:resource_territory', 'id': 'utility:resource_territory' }, + { 'iconName': 'utility:restriction_policy', 'id': 'utility:restriction_policy' }, + { 'iconName': 'utility:retail_execution', 'id': 'utility:retail_execution' }, + { 'iconName': 'utility:retweet', 'id': 'utility:retweet' }, + { 'iconName': 'utility:ribbon', 'id': 'utility:ribbon' }, + { 'iconName': 'utility:richtextbulletedlist', 'id': 'utility:richtextbulletedlist' }, + { 'iconName': 'utility:richtextindent', 'id': 'utility:richtextindent' }, + { 'iconName': 'utility:richtextnumberedlist', 'id': 'utility:richtextnumberedlist' }, + { 'iconName': 'utility:richtextoutdent', 'id': 'utility:richtextoutdent' }, + { 'iconName': 'utility:right', 'id': 'utility:right' }, + { 'iconName': 'utility:right_align', 'id': 'utility:right_align' }, + { 'iconName': 'utility:right_align_text', 'id': 'utility:right_align_text' }, + { 'iconName': 'utility:rotate', 'id': 'utility:rotate' }, + { 'iconName': 'utility:routing_offline', 'id': 'utility:routing_offline' }, + { 'iconName': 'utility:rows', 'id': 'utility:rows' }, + { 'iconName': 'utility:rules', 'id': 'utility:rules' }, + { 'iconName': 'utility:salesforce_page', 'id': 'utility:salesforce_page' }, + { 'iconName': 'utility:salesforce1', 'id': 'utility:salesforce1' }, + { 'iconName': 'utility:save', 'id': 'utility:save' }, + { 'iconName': 'utility:screen', 'id': 'utility:screen' }, + { 'iconName': 'utility:search', 'id': 'utility:search' }, + { 'iconName': 'utility:section', 'id': 'utility:section' }, + { 'iconName': 'utility:send', 'id': 'utility:send' }, + { 'iconName': 'utility:sentiment_negative', 'id': 'utility:sentiment_negative' }, + { 'iconName': 'utility:sentiment_neutral', 'id': 'utility:sentiment_neutral' }, + { 'iconName': 'utility:serialized_product', 'id': 'utility:serialized_product' }, + { 'iconName': 'utility:serialized_product_transaction', 'id': 'utility:serialized_product_transaction' }, + { 'iconName': 'utility:service_territory_policy', 'id': 'utility:service_territory_policy' }, + { 'iconName': 'utility:settings', 'id': 'utility:settings' }, + { 'iconName': 'utility:setup', 'id': 'utility:setup' }, + { 'iconName': 'utility:setup_assistant_guide', 'id': 'utility:setup_assistant_guide' }, + { 'iconName': 'utility:setup_modal', 'id': 'utility:setup_modal' }, + { 'iconName': 'utility:share', 'id': 'utility:share' }, + { 'iconName': 'utility:share_file', 'id': 'utility:share_file' }, + { 'iconName': 'utility:share_mobile', 'id': 'utility:share_mobile' }, + { 'iconName': 'utility:share_post', 'id': 'utility:share_post' }, + { 'iconName': 'utility:shield', 'id': 'utility:shield' }, + { 'iconName': 'utility:shift_pattern', 'id': 'utility:shift_pattern' }, + { 'iconName': 'utility:shift_pattern_entry', 'id': 'utility:shift_pattern_entry' }, + { 'iconName': 'utility:shift_scheduling_operation', 'id': 'utility:shift_scheduling_operation' }, + { 'iconName': 'utility:shift_ui', 'id': 'utility:shift_ui' }, + { 'iconName': 'utility:shopping_bag', 'id': 'utility:shopping_bag' }, + { 'iconName': 'utility:shortcuts', 'id': 'utility:shortcuts' }, + { 'iconName': 'utility:side_list', 'id': 'utility:side_list' }, + { 'iconName': 'utility:signpost', 'id': 'utility:signpost' }, + { 'iconName': 'utility:skip', 'id': 'utility:skip' }, + { 'iconName': 'utility:skip_back', 'id': 'utility:skip_back' }, + { 'iconName': 'utility:skip_forward', 'id': 'utility:skip_forward' }, + { 'iconName': 'utility:slider', 'id': 'utility:slider' }, + { 'iconName': 'utility:smiley_and_people', 'id': 'utility:smiley_and_people' }, + { 'iconName': 'utility:sms', 'id': 'utility:sms' }, + { 'iconName': 'utility:snippet', 'id': 'utility:snippet' }, + { 'iconName': 'utility:sobject', 'id': 'utility:sobject' }, + { 'iconName': 'utility:sobject_collection', 'id': 'utility:sobject_collection' }, + { 'iconName': 'utility:socialshare', 'id': 'utility:socialshare' }, + { 'iconName': 'utility:sort', 'id': 'utility:sort' }, + { 'iconName': 'utility:sort_policy', 'id': 'utility:sort_policy' }, + { 'iconName': 'utility:spinner', 'id': 'utility:spinner' }, + { 'iconName': 'utility:stage', 'id': 'utility:stage' }, + { 'iconName': 'utility:stage_collection', 'id': 'utility:stage_collection' }, + { 'iconName': 'utility:standard_objects', 'id': 'utility:standard_objects' }, + { 'iconName': 'utility:steps', 'id': 'utility:steps' }, + { 'iconName': 'utility:stop', 'id': 'utility:stop' }, + { 'iconName': 'utility:store', 'id': 'utility:store' }, + { 'iconName': 'utility:strategy', 'id': 'utility:strategy' }, + { 'iconName': 'utility:strikethrough', 'id': 'utility:strikethrough' }, + { 'iconName': 'utility:success', 'id': 'utility:success' }, + { 'iconName': 'utility:summary', 'id': 'utility:summary' }, + { 'iconName': 'utility:summarydetail', 'id': 'utility:summarydetail' }, + { 'iconName': 'utility:survey', 'id': 'utility:survey' }, + { 'iconName': 'utility:swarm_request', 'id': 'utility:swarm_request' }, + { 'iconName': 'utility:swarm_session', 'id': 'utility:swarm_session' }, + { 'iconName': 'utility:switch', 'id': 'utility:switch' }, + { 'iconName': 'utility:symbols', 'id': 'utility:symbols' }, + { 'iconName': 'utility:sync', 'id': 'utility:sync' }, + { 'iconName': 'utility:system_and_global_variable', 'id': 'utility:system_and_global_variable' }, + { 'iconName': 'utility:table', 'id': 'utility:table' }, + { 'iconName': 'utility:table_settings', 'id': 'utility:table_settings' }, + { 'iconName': 'utility:tablet_landscape', 'id': 'utility:tablet_landscape' }, + { 'iconName': 'utility:tablet_portrait', 'id': 'utility:tablet_portrait' }, + { 'iconName': 'utility:tabset', 'id': 'utility:tabset' }, + { 'iconName': 'utility:talent_development', 'id': 'utility:talent_development' }, + { 'iconName': 'utility:target', 'id': 'utility:target' }, + { 'iconName': 'utility:target_mode', 'id': 'utility:target_mode' }, + { 'iconName': 'utility:task', 'id': 'utility:task' }, + { 'iconName': 'utility:text', 'id': 'utility:text' }, + { 'iconName': 'utility:text_background_color', 'id': 'utility:text_background_color' }, + { 'iconName': 'utility:text_color', 'id': 'utility:text_color' }, + { 'iconName': 'utility:text_template', 'id': 'utility:text_template' }, + { 'iconName': 'utility:textarea', 'id': 'utility:textarea' }, + { 'iconName': 'utility:textbox', 'id': 'utility:textbox' }, + { 'iconName': 'utility:threedots', 'id': 'utility:threedots' }, + { 'iconName': 'utility:threedots_vertical', 'id': 'utility:threedots_vertical' }, + { 'iconName': 'utility:thunder', 'id': 'utility:thunder' }, + { 'iconName': 'utility:tile_card_list', 'id': 'utility:tile_card_list' }, + { 'iconName': 'utility:toggle', 'id': 'utility:toggle' }, + { 'iconName': 'utility:toggle_panel_bottom', 'id': 'utility:toggle_panel_bottom' }, + { 'iconName': 'utility:toggle_panel_left', 'id': 'utility:toggle_panel_left' }, + { 'iconName': 'utility:toggle_panel_right', 'id': 'utility:toggle_panel_right' }, + { 'iconName': 'utility:toggle_panel_top', 'id': 'utility:toggle_panel_top' }, + { 'iconName': 'utility:top_align', 'id': 'utility:top_align' }, + { 'iconName': 'utility:topic', 'id': 'utility:topic' }, + { 'iconName': 'utility:topic2', 'id': 'utility:topic2' }, + { 'iconName': 'utility:touch_action', 'id': 'utility:touch_action' }, + { 'iconName': 'utility:tracker', 'id': 'utility:tracker' }, + { 'iconName': 'utility:trail', 'id': 'utility:trail' }, + { 'iconName': 'utility:trailblazer_ext', 'id': 'utility:trailblazer_ext' }, + { 'iconName': 'utility:trailhead', 'id': 'utility:trailhead' }, + { 'iconName': 'utility:trailhead_alt', 'id': 'utility:trailhead_alt' }, + { 'iconName': 'utility:trailhead_ext', 'id': 'utility:trailhead_ext' }, + { 'iconName': 'utility:transparent', 'id': 'utility:transparent' }, + { 'iconName': 'utility:travel_and_places', 'id': 'utility:travel_and_places' }, + { 'iconName': 'utility:trending', 'id': 'utility:trending' }, + { 'iconName': 'utility:turn_off_notifications', 'id': 'utility:turn_off_notifications' }, + { 'iconName': 'utility:type', 'id': 'utility:type' }, + { 'iconName': 'utility:type_tool', 'id': 'utility:type_tool' }, + { 'iconName': 'utility:undelete', 'id': 'utility:undelete' }, + { 'iconName': 'utility:undeprecate', 'id': 'utility:undeprecate' }, + { 'iconName': 'utility:underline', 'id': 'utility:underline' }, + { 'iconName': 'utility:undo', 'id': 'utility:undo' }, + { 'iconName': 'utility:unlinked', 'id': 'utility:unlinked' }, + { 'iconName': 'utility:unlock', 'id': 'utility:unlock' }, + { 'iconName': 'utility:unmuted', 'id': 'utility:unmuted' }, + { 'iconName': 'utility:up', 'id': 'utility:up' }, + { 'iconName': 'utility:upload', 'id': 'utility:upload' }, + { 'iconName': 'utility:user', 'id': 'utility:user' }, + { 'iconName': 'utility:user_role', 'id': 'utility:user_role' }, + { 'iconName': 'utility:variable', 'id': 'utility:variable' }, + { 'iconName': 'utility:variation_attribute_setup', 'id': 'utility:variation_attribute_setup' }, + { 'iconName': 'utility:variation_products', 'id': 'utility:variation_products' }, + { 'iconName': 'utility:video', 'id': 'utility:video' }, + { 'iconName': 'utility:voicemail_drop', 'id': 'utility:voicemail_drop' }, + { 'iconName': 'utility:volume_high', 'id': 'utility:volume_high' }, + { 'iconName': 'utility:volume_low', 'id': 'utility:volume_low' }, + { 'iconName': 'utility:volume_off', 'id': 'utility:volume_off' }, + { 'iconName': 'utility:waits', 'id': 'utility:waits' }, + { 'iconName': 'utility:warning', 'id': 'utility:warning' }, + { 'iconName': 'utility:warranty_term', 'id': 'utility:warranty_term' }, + { 'iconName': 'utility:watchlist', 'id': 'utility:watchlist' }, + { 'iconName': 'utility:weeklyview', 'id': 'utility:weeklyview' }, + { 'iconName': 'utility:wellness', 'id': 'utility:wellness' }, + { 'iconName': 'utility:wifi', 'id': 'utility:wifi' }, + { 'iconName': 'utility:work_forecast', 'id': 'utility:work_forecast' }, + { 'iconName': 'utility:work_order_type', 'id': 'utility:work_order_type' }, + { 'iconName': 'utility:world', 'id': 'utility:world' }, + { 'iconName': 'utility:yubi_key', 'id': 'utility:yubi_key' }, + { 'iconName': 'utility:zoomin', 'id': 'utility:zoomin' }, + { 'iconName': 'utility:zoomout', 'id': 'utility:zoomout' } + +] + +const ICON_CATEGORIES = [ 'standard', 'custom', 'utility', 'action']; + +const MODES = { + ACCORDION: 'accordion', + TAB: 'tab', + COMBOBOX: 'combobox' +} +const CLASSES = { + OPEN: 'slds-is-open' +} + +const SEARCHBOX_ICONS = { + CLEAR: 'utility:clear', + SEARCH: 'utility:search' +} + +const DEFAULT_MAX_RESULTS = 100; + +const columns = [ + { label: 'Icon', fieldName: 'id', cellAttributes: { iconName: { fieldName: 'iconName' } } } +]; +export default class ObjectIconSelector extends LightningElement { + + @track actionIcons = ACTION_ICONS; + @track customIcons = CUSTOM_ICONS; + @track utilityIcons = UTILITY_ICONS; + @track standardIcons = STANDARD_ICONS; + + @track icons = []; + @track columns = columns; + + @api hideStandardIcons; + @api hideCustomIcons; + @api hideUtilityIcons; + @api hideActionIcons; + + @api + get iconCategories() { + return this._iconCategories; + } + set iconCategories(iconCategories) { + this._iconCategories = iconCategories; + for (let category of ICON_CATEGORIES) { + let hideProperty = 'hide' + category.charAt(0).toUpperCase() + category.slice(1) +'Icons'; + this[hideProperty] = !iconCategories.includes(category); + } + + } + + @api mode; + @api label = 'Pick an Icon'; + + // accordionMode is a legacy property added for backwards compatability and is not recommended for future use + @api + get accordionMode() { + return this._accordionMode; + } + set accordionMode(isAccMode) { + this._accordionMode = isAccMode; + this.mode = isAccMode ? MODES.ACCORDION : MODES.TAB; + } + _accordionMode; + + @api + get iconName() { + return this._iconName || null; + } + set iconName(iconName) { + this._iconName = iconName; + if (!this.rendered) { + return; + } + if (this.comboboxMode) { + this.setComboboxFormatting(); + } + const iconSelectedEvent = new CustomEvent('iconselection', { detail: iconName }); + this.dispatchEvent(iconSelectedEvent); + } + _iconName; + + activeSections = []; // 'S', 'U', 'C', 'A' + maxResults = DEFAULT_MAX_RESULTS + currentMaxResults = this.maxResults; + searchText; + noMatchesFoundString = 'No matches found'; + blockBlur; + rendered; + + + @api isAccordionLoading; // Reserved for future improvements + @api iconPickerButtonLabel; // reserved for future improvements + + @api + get tabStyle() { + let style; + if (this.firstTabHeight) { + style = `height: ${this.firstTabHeight}px`; + } + return style; + } + + @api + get tableStyle() { + return TABLE_STYLE; + } + + @api firstTabHeight; + + get tabMode() { return this.mode === MODES.TAB; } + get accordionMode() { return this.mode === MODES.ACCORDION; } + get comboboxMode() { return this.mode === MODES.COMBOBOX; } + get invalidMode() { return !this.tabMode && !this.accordionMode && !this.comboboxMode; } + + get displayedIcons() { + return this.filteredIcons.slice(0, this.currentMaxResults); + } + + get filteredIcons() { + if (!this.searchText) + return this.icons; + + return this.icons.filter(icon => { + return icon.iconName.toLowerCase().includes(this.searchText); + }); + } + + get resultsExceedMax() { + return this.filteredIcons.length > this.currentMaxResults; + } + + get loadMoreString() { + return 'Load more (' + this.currentMaxResults + ' of ' + this.filteredIcons.length + ' ' + (this.searchText ? 'matches' : 'options') + ' displayed)'; + } + + get searchboxIcon() { + return (this.searchText || this.iconName) ? SEARCHBOX_ICONS.CLEAR : SEARCHBOX_ICONS.SEARCH; + } + + get iconOptions() { + return this.icons.map(icon => { + return { + label: icon.iconName, + value: icon.iconName, + icon: icon.iconName + } + }); + } + + connectedCallback() { + if (!this.hideStandardIcons) this.icons.push(...this.standardIcons); + if (!this.hideCustomIcons) this.icons.push(...this.customIcons); + if (!this.hideUtilityIcons) this.icons.push(...this.utilityIcons); + // Action icons display weirdly in the combobox so I'm leaving them out for now + //if (!this.hideActionIcons) this.icons.push(...this.actionIcons); + } + + renderedCallback() { + if (this.rendered) return; + this.rendered = true; + + if (this.iconName) + this.iconName = this.iconName; + + } + + iconSelected(event) { + const selRow = event.detail.selectedRows[0]; + this.iconName = selRow.iconName; + // Moving the dispatch to iconName setter + // const iconSelectedEvent = new CustomEvent('iconselection', { detail: this.iconName }); + // this.dispatchEvent(iconSelectedEvent); + } + + + doSearch(searchText) { + this.searchText = searchText ? searchText.toLowerCase() : null; + this.showList(); + } + + showList() { + this.addClass('.slds-dropdown-trigger', CLASSES.OPEN); + this.focusSearchbox(); + } + + hideList() { + this.removeClass('.slds-dropdown-trigger', CLASSES.OPEN); + } + + loadMore() { + this.currentMaxResults += this.maxResults; + } + + focusSearchbox() { + this.template.querySelector('.comboboxInput').focus(); + } + + blurSearchbox() { + this.template.querySelector('.comboboxInput').blur(); + } + + clearSearchbox() { + this.iconName = null; + this.blockBlur = true; + this.doSearch(); + } + + setComboboxFormatting() { + if (this.iconName) { + this.addClass('.comboboxInput', 'slds-combobox__input-value'); + this.switchClass('.slds-combobox__form-element', 'slds-input-has-icon_right', 'slds-input-has-icon_left-right'); + this.addClass('.slds-combobox_container', 'slds-has-selection'); + this.template.querySelector('.comboboxInput').setAttribute('readonly', ''); + this.template.querySelector('.comboboxInput').value = this.iconName; + this.blurSearchbox(); + } else { + this.removeClass('.comboboxInput', 'slds-combobox__input-value'); + this.switchClass('.slds-combobox__form-element', 'slds-input-has-icon_left-right', 'slds-input-has-icon_right'); + this.removeClass('.slds-combobox_container', 'slds-has-selection'); + this.template.querySelector('.comboboxInput').removeAttribute('readonly'); + this.template.querySelector('.comboboxInput').value = null; + } + } + + + /* EVENT HANDLERS */ + handleIconSelect(event) { + let icon = event.currentTarget.dataset.icon; + this.iconName = icon; + } + + handleSearchFocus(event) { + if (!this.iconName) + this.doSearch(event.currentTarget.value); + } + + handleSearchChange(event) { + this.doSearch(event.currentTarget.value); + } + + handleSearchBlur() { + if (this.blockBlur) { + this.focusSearchbox(); + this.blockBlur = false; + } else { + this.currentMaxResults = this.maxResults; + this.hideList(); + } + } + + handleDropdownClick() { + this.blockBlur = true; + } + + handleSearchboxIconClick(event) { + if (event.currentTarget.iconName == SEARCHBOX_ICONS.CLEAR) { + this.clearSearchbox(); + } else { + this.doSearch(); + } + } + + handleComboboxChange(event) { + this.iconName = event.detail.value; + } + + /* UTITLITY FUNCTIONS */ + addClass(selector, className) { + let el = this.template.querySelector(selector); + if (el) + el.classList.add(className); + return !!el; + } + + removeClass(selector, className) { + let el = this.template.querySelector(selector); + if (el) + el.classList.remove(className); + return !!el; + } + + switchClass(selector, removeClass, addClass) { + this.removeClass(selector, removeClass); + this.addClass(selector, addClass); + } + + /* LEGACY PROPERTIES */ + @api showAccordion; + @api hideAccordion; +} diff --git a/force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml b/force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml new file mode 100644 index 0000000..d27a5dc --- /dev/null +++ b/force-app/main/default/lwc/iconSelector/iconSelector.js-meta.xml @@ -0,0 +1,29 @@ + + + 51.0 + true + Pick an Icon + Icon Picker + + lightning__FlowScreen + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js b/force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js new file mode 100644 index 0000000..22734a3 --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/__tests__/indicatorBuilder.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import IndicatorBuilder from 'c/indicatorBuilder'; + +describe('c-indicator-builder', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-indicator-builder', { + is: IndicatorBuilder + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css new file mode 100644 index 0000000..e0f8947 --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css @@ -0,0 +1,7 @@ +.slds-vertical-tabs, .slds-vertical-tabs * { + overflow: visible; +} + +.slds-vertical-tabs__content{ + overflow: visible; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html new file mode 100644 index 0000000..2af9a7c --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html @@ -0,0 +1,157 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js new file mode 100644 index 0000000..dae35cf --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js @@ -0,0 +1,201 @@ +import { LightningElement, api, track } from 'lwc'; + +export default class IndicatorBuilder extends LightningElement { + indSize = 'large'; + @api indShape = 'base'; + @api indText = ''; + @api indImage = ''; + indIcon = 'standard:marketing_actions'; + @api indHoverText = ''; + indBackgroundColor; + indForegroundColor; + + showMatch = {}; + iconSource = {} + showTextMatch = false; + showNumberMatch = false; + overrideColours = false; + + get activeVariantTabIndex() { + return this._activeVariantTabIndex; + } + set activeVariantTabIndex(value) { + this._activeVariantTabIndex = value; + this.itemVariants = this.itemVariants.map((variant, index) => { + variant.isActive = index == this.activeVariantTabIndex; + return variant; + }); + } + _activeVariantTabIndex = 0; + + @track itemVariants = []; + // { label: 'Default Indicator' } + // this.newIndicatorVariant('Default Indicator') + + + whenToDisplayOptions = [ + { label: 'Is not blank', value: 'notBlank' }, + { label: 'Is blank', value: 'isBlank' }, + { label: 'Contains text', value: 'containsText', showMatch: 'text' }, + { label: 'Equals text', value: 'equalsText', showMatch: 'text' }, + { label: 'Equals number', value: 'equalsNumber', showMatch: 'number' }, + { label: 'Is greater than', value: 'greaterThan', showMatch: 'number' }, + { label: 'Is less than', value: 'lessThan', showMatch: 'number' }, + { label: 'Is within range', value: 'inRange', showMatch: 'numericRange' }, + { label: 'Custom formula', value: 'customFormula' }, + { label: 'Custom exception', value: 'customException' }, + ]; + + iconSourceOptions = [ + { label: 'Lightning Icon', value: 'sldsIcon' }, + { label: 'Static Text', value: 'staticText' }, + { label: 'URL', value: 'url' }, + { label: 'Static Resource', value: 'staticResource' }, + ]; + + iconSizeOptions = [ + { label: 'x-small', value: 'x-small' }, + { label: 'small', value: 'small' }, + { label: 'medium', value: 'medium', default: true }, + { label: 'large', value: 'large' }, + ]; + + fieldLabelOptions = [ + { label: 'Hide field label', value: 'hide' }, + { label: 'Show standard label', value: 'standard' }, + { label: 'Show custom label', value: 'custom' }, + ] + + get showColourOption() { + return this.iconSource.sldsIcon || this.iconSource.staticText; + } + + get showColourSelectors() { + return this.showColourOption && this.overrideColours; + } + + connectedCallback() { + if (this.itemVariants.length === 0) { + console.log(`adding default variants`); + this.addNewVariant('When field has value', 'notBlank'); + this.addNewVariant('When field is blank', 'isBlank'); + this.activeVariantTabIndex = 0; + } + } + + handleWhenToDisplayChange(event) { + let value = event.detail.value; + let matchingOption = this.whenToDisplayOptions.find(option => option.value == value); + if (matchingOption) { + this.showMatch = { [matchingOption.showMatch]: true }; + } + } + + handleIconSourceChange(event) { + let value = event.detail.value; + let variantToUpdate = this.itemVariants[target.dataset.index]; + console.log(`value = ${value}`); + // this.iconSource = { [value]: true }; + variantToUpdate.iconSource = { [value]: true }; + } + + handleIconSelection(event) { + console.log(JSON.stringify(event.detail)); + this.indIcon = event.detail; + } + + handleStaticTextChange(event) { + this.indText = event.target.value; + } + + handleForegroundColourChange(event) { + this.indForegroundColor = event.target.value; + } + + handleBackgroundColourChange(event) { + this.indBackgroundColor = event.target.value; + } + + handleOverideColoursChange(event) { + this.overrideColours = event.target.checked; + } + + handleAddVariantClick() { + // this.itemVariants.push({ label: `Indicator Variant ${(this.itemVariants.length + 1)}`}); + // this.itemVariants.push(this.newIndicatorVariant(`Indicator Variant ${(this.itemVariants.length + 1)}`)); + this.addNewVariant(`Indicator Variant ${(this.itemVariants.length + 1)}`); + } + + handleTabAnchorClick(event) { + console.log(`in handleTabAnchorClick`); + this.activeVariantTabIndex = event.currentTarget.dataset.index; + console.log(`activeVariantTabIndex = ${this.activeVariantTabIndex}`); + } + + handleVariantPropertyChange(event) { + if (event.currentTarget.dataset.property) { + let target = event.currentTarget; + let tagName = target.tagName.toLowerCase(); + let value; + if (tagName === 'c-icon-selector') { + value = event.detail; + } else if (target.type === 'checkbox') { + value = target.checked; + } else if (tagName === 'lightning-combobox') { + value = event.detail.value; + } else { + value = target.value; + } + + console.log(`index is ${target.dataset.index}, value is ${value}, property name is ${target.dataset.property}`); + + let variantToUpdate = this.itemVariants[target.dataset.index]; + if (variantToUpdate) { + variantToUpdate[target.dataset.property] = value; + if (target.dataset.property === 'iconSource') { + variantToUpdate.sourceValue = null; + } + this.itemVariants = [...this.itemVariants]; + console.log(`updated variant value = ${JSON.stringify(variantToUpdate)}`); + } + } + } + + addNewVariant(label, whenToDisplay) { + this.itemVariants.push(this.newIndicatorVariant(label, whenToDisplay)); + this.activeVariantTabIndex = this.itemVariants.length - 1; + } + + newIndicatorVariant(label, whenToDisplay, isActive = true, iconSource = 'sldsIcon') { + let whenToDisplayOptions = this.whenToDisplayOptions; + + let newVariant = { + label, + whenToDisplay, + isActive, + iconSource, + hoverText: '', + get iconSourceIs() { + return { [this.iconSource]: true } + }, + get filterTypeIs() { + let matchingOption = whenToDisplayOptions.find(option => option.value == this.whenToDisplay); + return matchingOption ? { [matchingOption.showMatch]: true } : {}; + }, + get tabAnchorClass() { + return 'slds-vertical-tabs__nav-item' + (this.isActive ? ' slds-is-active' : ''); + }, + get tabPaneClass() { + return 'slds-vertical-tabs__content ' + (this.isActive ? 'slds-show' : 'slds-hide'); + }, + get showColourOption() { + return this.iconSourceIs.sldsIcon; + }, + get showColourSelectors() { + return this.iconSourceIs.staticText || (this.showColourOption && this.overrideColours); + } + } + console.log(`newVariant = ${JSON.stringify(newVariant)}`); + return newVariant; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml new file mode 100644 index 0000000..f6b2657 --- /dev/null +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js-meta.xml @@ -0,0 +1,8 @@ + + + 58.0 + true + + lightning__Tab + + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js index 2d23e31..4872229 100644 --- a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js +++ b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js @@ -2,34 +2,84 @@ import { LightningElement, api } from 'lwc'; export default class IndicatorListItem extends LightningElement { @api indSize = 'large'; - @api indShape = 'base'; - @api indText = ''; - @api indImage = ''; - @api indIcon = 'standard:marketing_actions'; - @api indHoverText = ''; - @api indBackgroundColor; - @api indForegroundColor; + // @api indShape = 'base'; + // @api indText = ''; + // @api indImage = ''; + // @api indIcon = 'standard:all' ; + // @api indHoverText = ''; - get indClass() { - let classValue = ''; - if(this.indBackgroundColor || this.indForegroundColor){ - classValue = 'indicatorIcon '; + @api iconSource; + @api sourceValue; + + @api get indBackgroundColor() { + return this._indBackgroundColor; + }; + set indBackgroundColor(value) { + this._indBackgroundColor = value; + if (this.iconElement) { + this.iconElement.style.setProperty('--backgroundColor', this.indBackgroundColor); + console.log(`setting background colour to ${this.indBackgroundColor}`); + } else { + console.log(`iconElement not found`); + } + } + _indBackgroundColor; + @api get indForegroundColor() { + return this._indForegroundColor; + }; + set indForegroundColor(value) { + this._indForegroundColor = value; + if (this.iconElement) { + this.iconElement.style.setProperty('--foregroundColor', this.indForegroundColor); + console.log(`setting foreground colour to ${this.indForegroundColor}`); + } else { + console.log(`iconElement not found`); } + } + _indForegroundColor; + + get indClass() { + let classValue = ['indicatorIcon']; + // if(this.indBackgroundColor || this.indForegroundColor){ + // classValue = 'indicatorIcon '; + // } if(this.indSize == 'large'){ - classValue += 'slds-var-m-right_small slds-var-m-vertical_medium'; + classValue.push('slds-var-m-right_small','slds-var-m-vertical_medium'); } else { - classValue += 'slds-var-m-right_x-small slds-var-m-vertical_small'; + classValue.push('slds-var-m-right_x-small', 'slds-var-m-vertical_small'); } if(this.indIcon == 'none'){ - classValue += 'slds-var-m-right_xxx-small slds-var-m-vertical_small slds-avatar__initials_inverse' + classValue.push('slds-var-m-right_xxx-small', 'slds-var-m-vertical_small', 'slds-avatar__initials_inverse'); + } + return classValue.join(' '); + } + + get iconElement() { + return this.template.querySelector(".indicatorIcon"); + } + + get indText() { + return (this.iconSource === 'staticText') ? (this.sourceValue || ' ') : ''; + } + + get indUrl() { + return (this.iconSource === 'url' || this.iconSource === 'staticResource') ? this.sourceValue : ''; + } + + get indIcon() { + if (this.iconSource === 'sldsIcon') { + return this.sourceValue; + } else if (this.iconSource === 'staticText') { + return 'standard:empty'; + } else { + return ''; } - - return classValue; } + /* No longer need to set CSS on renderedCallback because it's controlled in setters for colors renderedCallback() { this.initCSSVariables(); } @@ -44,4 +94,5 @@ export default class IndicatorListItem extends LightningElement { } } + */ } \ No newline at end of file From a524b32a2da69d2a708033c5ca67134eb1078d01 Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Tue, 31 Oct 2023 15:36:05 -0500 Subject: [PATCH 06/23] Added CSS line to change utility icon foreground --- .../main/default/lwc/indicatorBundleItem/indicatorBundleItem.css | 1 + 1 file changed, 1 insertion(+) diff --git a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css index 401ae97..a243f13 100644 --- a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css +++ b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.css @@ -3,6 +3,7 @@ } .indicatorIcon { + --slds-c-icon-color-foreground-default: var(--foregroundColor); --slds-c-icon-color-foreground: var(--foregroundColor); --slds-c-icon-color-background: var(--backgroundColor); --slds-c-avatar-text-color: var(--foregroundColor); From e96a508c4c0fb9b9b5bcef7d0e83b0d40589411a Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Tue, 31 Oct 2023 15:52:35 -0500 Subject: [PATCH 07/23] Adding objectFieldSelector --- .../fsc_objectFieldSelector.html | 28 +++ .../fsc_objectFieldSelector.js | 189 ++++++++++++++++++ .../fsc_objectFieldSelector.js-meta.xml | 32 +++ .../indicatorBundleItem.js | 2 +- 4 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js create mode 100644 force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html new file mode 100644 index 0000000..54c3a73 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js new file mode 100644 index 0000000..2b3cf2d --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js @@ -0,0 +1,189 @@ +import { LightningElement, api, track } from 'lwc'; +import { FlowAttributeChangeEvent } from 'lightning/flowSupport'; + +import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_comboboxUtils'; + +export default class Fsc_objectFieldSelector extends LightningElement { + availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); + + @api name; + @api masterLabel; + @api objectLabel = 'Select Object'; + @api fieldLabel = 'Select Field'; + @api valueDelimiter = ','; + + @api disableObjectPicklist = false; + @api hideObjectPicklist = false; + @api hideFieldPicklist = false; + @api objectAllowMultiselect = false; + @api fieldAllowMultiselect = false; + @api required = false; + + @api availableObjectSelection = this.availableObjectOptions.default?.value; + @api availableObjects; + @api availableFieldTypes; + @api availableReferenceTypes; + @api lockDefaultObject; + @api defaultToNameField; + @api layout = LAYOUT_OPTIONS.VERTICAL.value; + + @api + get builderContext() { + return this._builderContext; + } + set builderContext(value) { + console.log('setting builderContext'); + console.log(JSON.stringify(value)); + this._builderContext = value; + } + _builderContext; + + @api + get objectValues() { + return this._objectValues || []; + } + set objectValues(values) { + this._objectValues = setValuesFromMultipleInput(values); + } + @track _objectValues = []; + + @api + get objectValue() { + return this.objectValues.join(this.valueDelimiter); + } + set objectValue(value) { + console.log('in set objectValue'); + console.log(value); + this.objectValues = setValuesFromSingularInput(value, this.valueDelimiter, this.objectAllowMultiselect); + } + + @api + get fieldValues() { + return this._fieldValues || []; + } + set fieldValues(values) { + this._fieldValues = setValuesFromMultipleInput(values); + } + @track _fieldValues = []; + + @api + get fieldValue() { + return this.fieldValues.join(this.valueDelimiter); + } + set fieldValue(value) { + this.fieldValues = setValuesFromSingularInput(value, this.valueDelimiter, this.fieldAllowMultiselect); + } + + + @api + get displayType() { + return this._displayType; + } + set displayType(value) { + this._displayType = value; + if (this.displayType === DISPLAY_TYPE_OPTIONS.FIELD.value) { + this.hideObjectPicklist = true; + } + if (this.displayType === DISPLAY_TYPE_OPTIONS.OBJECT.value) { + this.hideFieldPicklist = true; + } + } + + @api + reportValidity() { + let isValid = true; + if (this.objectSelector) { + isValid = this.objectSelector.reportValidity() && isValid; + } + if (this.fieldSelector) { + isValid = this.fieldSelector.reportValidity() && isValid; + } + return isValid; + } + + @api + validate() { + let errorMessages = [] + const validateComponents = [this.objectSelector, this.fieldSelector]; + validateComponents.forEach(cmp => { + if (cmp?.validate().errorMessage) { + errorMessages.push(cmp.validate().errorMessage) + } + }) + // if (this.objectSelector && this.objectSelector.validate().errorMessage) { + // errorMessages.push(this.objectSelector.validate().errorMessage) + // } + // if (this.fieldSelector && this.fieldSelector.validate().errorMessage) { + // errorMessages.push(this.fieldSelector.validate().errorMessage) + // } + console.log('in ofsValidate, errorMessages = ' + errorMessages); + if (errorMessages.length) { + return { + isValid: false, + errorMessage: errorMessages.join(' ') + }; + } else { + return { isValid: true }; + } + } + + get computedColClass() { + let classString = 'slds-col'; + if (this.displayType === DISPLAY_TYPE_OPTIONS.BOTH.value && this.layout === LAYOUT_OPTIONS.HORIZONTAL.value) { + classString += ' slds-size_1-of-2'; + } else { + classString += ' slds-size_1-of-1'; + } + return classString; + } + + get objectSelector() { + return this.template.querySelector('c-fsc_object-selector'); + } + + get fieldSelector() { + return this.template.querySelector('c-fsc_field-selector2'); + } + + handleObjectChange(event) { + this.objectValue = event.detail.value; + const attributeChangeEvent = new FlowAttributeChangeEvent( + 'objectValue', + this.objectValue + ); + this.dispatchEvent(attributeChangeEvent); + this.dispatchValues(); + } + + handleFieldChange(event) { + this.fieldValue = event.detail.value; + const attributeChangeEvent = new FlowAttributeChangeEvent( + 'fieldValue', + this.fieldValue + ); + this.dispatchEvent(attributeChangeEvent); + this.dispatchValues(); + } + + dispatchValues() { + this.dispatchEvent(new CustomEvent('change', { + detail: { + objectValue: this.objectValue, + objectValues: this.objectValues, + fieldValue: this.fieldValue, + fieldValues: this.fieldValues + } + })); + } + + + connectedCallback() { + // console.log('displayType = ' + this.displayType); + // console.log('objectValue = ' + this.objectValue); + // console.log('availableFieldTypes = ' + this.availableFieldTypes); + // console.log('availableReferenceTypes = ' + this.availableReferenceTypes); + // console.log('hideObjectPicklist = ' + this.hideObjectPicklist); + // console.log('hideFieldPicklist = ' + this.hideFieldPicklist); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml new file mode 100644 index 0000000..498f554 --- /dev/null +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml @@ -0,0 +1,32 @@ + + + 54.0 + true + Object and Field Selector + + lightning__FlowScreen + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js index 4872229..7270149 100644 --- a/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js +++ b/force-app/main/default/lwc/indicatorBundleItem/indicatorBundleItem.js @@ -6,7 +6,7 @@ export default class IndicatorListItem extends LightningElement { // @api indText = ''; // @api indImage = ''; // @api indIcon = 'standard:all' ; - // @api indHoverText = ''; + @api indHoverText = ''; @api iconSource; @api sourceValue; From fe935ce42e13027375890cabb70bf815e73430c2 Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Wed, 7 Feb 2024 09:27:55 -0800 Subject: [PATCH 08/23] Changes to fieldSelector and objectFieldSelector. Added indicatorStyleConfig and indicatorUtils --- .../fsc_fieldSelector2/fsc_fieldSelector2.js | 18 +- .../fsc_objectFieldSelector.html | 2 +- .../fsc_objectFieldSelector.js | 15 +- .../fsc_objectFieldSelector.js-meta.xml | 1 - .../indicatorBuilder/indicatorBuilder.html | 275 ++++++++++-------- .../lwc/indicatorBuilder/indicatorBuilder.js | 216 +++++++++++--- .../__tests__/indicatorStyleConfig.test.js | 25 ++ .../indicatorStyleConfig.html | 75 +++++ .../indicatorStyleConfig.js | 60 ++++ .../indicatorStyleConfig.js-meta.xml | 5 + .../__tests__/indicatorUtils.test.js | 25 ++ .../lwc/indicatorUtils/indicatorUtils.js | 31 ++ .../indicatorUtils/indicatorUtils.js-meta.xml | 5 + 13 files changed, 582 insertions(+), 171 deletions(-) create mode 100644 force-app/main/default/lwc/indicatorStyleConfig/__tests__/indicatorStyleConfig.test.js create mode 100644 force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.html create mode 100644 force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js create mode 100644 force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js-meta.xml create mode 100644 force-app/main/default/lwc/indicatorUtils/__tests__/indicatorUtils.test.js create mode 100644 force-app/main/default/lwc/indicatorUtils/indicatorUtils.js create mode 100644 force-app/main/default/lwc/indicatorUtils/indicatorUtils.js-meta.xml diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js index df67709..25217c0 100644 --- a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js @@ -45,7 +45,7 @@ export default class Fsc_fieldSelector2 extends LightningElement { @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. - @api allowReferenceLookups = false; + @api allowReferenceLookups = false; @track fields = []; @track _values = []; @track _availableFieldTypes = []; @@ -199,7 +199,7 @@ export default class Fsc_fieldSelector2 extends LightningElement { fields = fields.filter(field => !field.referenceToInfos.length || field.referenceToInfos.some(ref => includesIgnoreCase(this.availableReferenceTypes, ref.apiName))); } } - this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, this.hideIcons ? null : this.getIconFromDataType(field.dataType))); + this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, field.dataType, this.hideIcons ? null : this.getIconFromDataType(field.dataType))); this.fields.sort((a, b) => { return a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1; }); @@ -216,12 +216,20 @@ export default class Fsc_fieldSelector2 extends LightningElement { } dispatchFields() { + let fieldData; + if (this.values.length) { + fieldData = this.fields.filter(field => this.values.includes(field.value)); + // { + // return this.values.find(value => field.apiName == value) + // }); + } let detail = { value: this.value, values: this.values, + fieldData: fieldData } this.dispatchEvent(new CustomEvent('change', { detail })); - } + } /* UTILITY FUNCTIONS */ getIconFromDataType(type) { @@ -229,7 +237,7 @@ export default class Fsc_fieldSelector2 extends LightningElement { return matchingType?.icon || DEFAULT_ICON; } - newField(label, sublabel, value, icon) { - return { label, sublabel, value, icon } + newField(label, sublabel, value, dataType, icon) { + return { label, sublabel, value, dataType, icon } } } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html index 54c3a73..8e2d7e2 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html @@ -20,7 +20,7 @@ allow-multiselect={fieldAllowMultiselect} object-name={objectValue} available-field-types={availableFieldTypes} available-reference-types={availableReferenceTypes} default-to-name-field={defaultToNameField} onchange={handleFieldChange} value={fieldValue} - builder-context={builderContext}> + builder-context={builderContext} allow-reference-lookups={allowReferenceLookups}> diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js index 2b3cf2d..c6760fa 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js @@ -6,6 +6,7 @@ import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_co export default class Fsc_objectFieldSelector extends LightningElement { availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); + displayTypeOptions = transformConstantObject(DISPLAY_TYPE_OPTIONS); @api name; @api masterLabel; @@ -18,6 +19,7 @@ export default class Fsc_objectFieldSelector extends LightningElement { @api hideFieldPicklist = false; @api objectAllowMultiselect = false; @api fieldAllowMultiselect = false; + @api allowReferenceLookups = false; @api required = false; @api availableObjectSelection = this.availableObjectOptions.default?.value; @@ -28,6 +30,8 @@ export default class Fsc_objectFieldSelector extends LightningElement { @api defaultToNameField; @api layout = LAYOUT_OPTIONS.VERTICAL.value; + @track fieldData; // used to retain all data from each seleted field, such as field data type + @api get builderContext() { return this._builderContext; @@ -53,8 +57,6 @@ export default class Fsc_objectFieldSelector extends LightningElement { return this.objectValues.join(this.valueDelimiter); } set objectValue(value) { - console.log('in set objectValue'); - console.log(value); this.objectValues = setValuesFromSingularInput(value, this.valueDelimiter, this.objectAllowMultiselect); } @@ -89,6 +91,7 @@ export default class Fsc_objectFieldSelector extends LightningElement { this.hideFieldPicklist = true; } } + _displayType = this.displayTypeOptions.default?.value; @api reportValidity() { @@ -117,7 +120,7 @@ export default class Fsc_objectFieldSelector extends LightningElement { // if (this.fieldSelector && this.fieldSelector.validate().errorMessage) { // errorMessages.push(this.fieldSelector.validate().errorMessage) // } - console.log('in ofsValidate, errorMessages = ' + errorMessages); + // console.log('in ofsValidate, errorMessages = ' + errorMessages); if (errorMessages.length) { return { isValid: false, @@ -158,6 +161,8 @@ export default class Fsc_objectFieldSelector extends LightningElement { handleFieldChange(event) { this.fieldValue = event.detail.value; + this.fieldData = event.detail.fieldData; + // console.log(`fieldData = ${JSON.stringify(this.fieldData)}`); const attributeChangeEvent = new FlowAttributeChangeEvent( 'fieldValue', this.fieldValue @@ -172,7 +177,9 @@ export default class Fsc_objectFieldSelector extends LightningElement { objectValue: this.objectValue, objectValues: this.objectValues, fieldValue: this.fieldValue, - fieldValues: this.fieldValues + fieldValues: this.fieldValues, + fieldData: this.fieldData + } })); } diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml index 498f554..3786f17 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml @@ -7,7 +7,6 @@ lightning__FlowScreen - diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html index 2af9a7c..91d51b2 100644 --- a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html @@ -16,142 +16,185 @@

- + +
+ + + + -
-
    - - -
+ \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js index dae35cf..38301ad 100644 --- a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js @@ -1,21 +1,64 @@ -import { LightningElement, api, track } from 'lwc'; +import { LightningElement, api, track, wire } from 'lwc'; +import { /* FIELD_TYPES ,*/ transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; +import { getObjectInfo } from "lightning/uiObjectInfoApi"; + +const FIELD_TYPES = { + TEXT: { value: 'text', default: true }, + NUMBER: { value: 'number', dataTypes: ['Integer', 'Double', 'Int', 'Long'] }, + DATE: { value: 'date', dataTypes: ['DateTime', 'Date', 'Time'] }, +} + +const SHOW_ONE_OR_ALL = { + SHOW_ONE: { label: 'the first variant with matching criteria', value: 'showOne', default: true }, + SHOW_ALL: { label: 'all variants with matching criteria', value: 'showAll' } + +} export default class IndicatorBuilder extends LightningElement { - indSize = 'large'; - @api indShape = 'base'; - @api indText = ''; - @api indImage = ''; - indIcon = 'standard:marketing_actions'; - @api indHoverText = ''; - indBackgroundColor; - indForegroundColor; + @api objectApiName = 'Account'; + @api fieldApiName = 'Name'; + @api fieldType; + @api showOneOrAll; + + // @wire(getObjectInfo, { objectApiName: "$objectApiName" }) + // wiredObjectInfo({ error, data }) { + // if (data) { + // console.log(`in wiredObjectInfo, found data`); + // let fieldData = data.fields[this.fieldApiName]; + // console.log(JSON.stringify(Object.keys(data.fields))); + // if (fieldData) { + // console.log(`found fieldData: ${JSON.stringify(fieldData)}`); + // } + // } + // } + + @track itemVariants = []; + + // indSize = 'large'; + // @api indShape = 'base'; + // @api indText = ''; + // @api indImage = ''; + // indIcon = 'standard:marketing_actions'; + // @api indHoverText; + // @api displayMode = 'showWhenValue'; + // indBackgroundColor; + // indForegroundColor; + showMatch = {}; - iconSource = {} - showTextMatch = false; - showNumberMatch = false; - overrideColours = false; - + // iconSource = {}; + + @track fieldTypes = transformConstantObject(FIELD_TYPES); + @track showOneOrAllOptions = transformConstantObject(SHOW_ONE_OR_ALL); + + // showTextMatch = false; + // showNumberMatch = false; + // overrideColors = false; + + get objectAndFieldSelected() { + return this.objectApiName && this.fieldApiName; + } + get activeVariantTabIndex() { return this._activeVariantTabIndex; } @@ -28,22 +71,53 @@ export default class IndicatorBuilder extends LightningElement { } _activeVariantTabIndex = 0; - @track itemVariants = []; - // { label: 'Default Indicator' } - // this.newIndicatorVariant('Default Indicator') - + get categorizedFieldType() { + let type = this.fieldTypes.options.find(fieldType => fieldType.dataTypes && fieldType.dataTypes.includes(this.fieldType)); + if (type) { + return type.value; + } else { + return this.fieldTypes.default.value; + } + // switch (this.fieldType) { + // case 'Integer': + // case 'Double': + // case 'Int': + // case 'Long': + // return 'number'; + // case 'DateTime': + // case 'Date': + // case 'Time': + // return 'date'; + // default: + // return '' + // } + } + + get filteredWhenToDisplayOptions() { + return this.whenToDisplayOptions.filter(option => !option.dataTypes || option.dataTypes.includes(this.categorizedFieldType)); + } + + get fieldTypeIsNumber() { + return this.categorizedFieldType === FIELD_TYPES.NUMBER.value; + } + + get itemVariantsString() { return JSON.stringify(this.itemVariants) }; + // { label: 'Default Indicator' } + // this.newIndicatorVariant('Default Indicator') + whenToDisplayOptions = [ { label: 'Is not blank', value: 'notBlank' }, { label: 'Is blank', value: 'isBlank' }, - { label: 'Contains text', value: 'containsText', showMatch: 'text' }, - { label: 'Equals text', value: 'equalsText', showMatch: 'text' }, - { label: 'Equals number', value: 'equalsNumber', showMatch: 'number' }, - { label: 'Is greater than', value: 'greaterThan', showMatch: 'number' }, - { label: 'Is less than', value: 'lessThan', showMatch: 'number' }, - { label: 'Is within range', value: 'inRange', showMatch: 'numericRange' }, - { label: 'Custom formula', value: 'customFormula' }, - { label: 'Custom exception', value: 'customException' }, + { label: 'Contains text', value: 'containsText', dataTypes: [FIELD_TYPES.TEXT.value], showMatch: 'text' }, + { label: 'Equals text', value: 'equalsText', dataTypes: [FIELD_TYPES.TEXT.value], showMatch: 'text' }, + { label: 'Starts with text', value: 'startsWithText', dataTypes: [FIELD_TYPES.TEXT.value], showMatch: 'text' }, + { label: 'Equals number', value: 'equalsNumber', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'number' }, + { label: 'Is greater than', value: 'greaterThan', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'number' }, + { label: 'Is less than', value: 'lessThan', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'number' }, + { label: 'Is within range', value: 'inRange', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'numericRange' }, + // { label: 'Custom formula', value: 'customFormula' }, + // { label: 'Custom exception', value: 'customException' }, ]; iconSourceOptions = [ @@ -64,23 +138,58 @@ export default class IndicatorBuilder extends LightningElement { { label: 'Hide field label', value: 'hide' }, { label: 'Show standard label', value: 'standard' }, { label: 'Show custom label', value: 'custom' }, - ] + ]; - get showColourOption() { - return this.iconSource.sldsIcon || this.iconSource.staticText; - } + displayModeOptions = [ + { label: 'Display indicator when field is populated, hide indicator when field is blank', value: 'showWhenValue' }, + { label: 'Display indicator when field is blank, hide indicator when field is populated', value: 'showWhenBlank' }, + { label: 'Display indicator based on custom logic', value: 'customLogic' }, + ]; - get showColourSelectors() { - return this.showColourOption && this.overrideColours; + // get showColorOption() { + // return this.iconSource.sldsIcon || this.iconSource.staticText; + // } + + // get showColorSelectors() { + // return this.showColorOption && this.overrideColors; + // } + + get indicator() { + if (this.itemVariants?.length) { + return this.itemVariants[0]; + } + return {}; } connectedCallback() { + console.log(`in indicatorBuilder connectedCallback`); if (this.itemVariants.length === 0) { console.log(`adding default variants`); - this.addNewVariant('When field has value', 'notBlank'); - this.addNewVariant('When field is blank', 'isBlank'); + this.addNewVariant('has a value', 'notBlank'); + this.addNewVariant('is blank', 'isBlank'); this.activeVariantTabIndex = 0; } + this.setDefaultValues(); + } + + setDefaultValues() { + if (!this.showOneOrAll) { + this.showOneOrAll = this.showOneOrAllOptions.default.value; + } + } + + handleObjectFieldSelectorChange(event) { + console.log(`in handleObjectFieldSelectorChange, event.detail = ${JSON.stringify(event.detail)}`); + if (!event.detail) { + console.log(`Error: no event.detail in handleObjectFieldSelectorChange`); + return; + } + this.objectApiName = event.detail.objectValue; + this.fieldApiName = event.detail.fieldValue; + if (event.detail.fieldData?.length) { + this.fieldType = event.detail.fieldData[0].dataType; + } + } handleWhenToDisplayChange(event) { @@ -108,16 +217,16 @@ export default class IndicatorBuilder extends LightningElement { this.indText = event.target.value; } - handleForegroundColourChange(event) { + handleForegroundColorChange(event) { this.indForegroundColor = event.target.value; } - handleBackgroundColourChange(event) { + handleBackgroundColorChange(event) { this.indBackgroundColor = event.target.value; } - - handleOverideColoursChange(event) { - this.overrideColours = event.target.checked; + + handleOverideColorsChange(event) { + this.overrideColors = event.target.checked; } handleAddVariantClick() { @@ -132,6 +241,22 @@ export default class IndicatorBuilder extends LightningElement { console.log(`activeVariantTabIndex = ${this.activeVariantTabIndex}`); } + // handleDisplayModeChange(event) { + // this.displayMode = event.detail.value; + // this.showVariantLogic = this.displayMode == 'customLogic'; + // } + + handleIndicatorChange(event) { + console.log(`in handleIndicatorChange, detail = ${JSON.stringify(event.detail)}`); + if (event.detail) { + let variantToUpdate = this.itemVariants[event.detail.index]; + if (variantToUpdate && event.detail.propertyName) { + variantToUpdate[event.detail.propertyName] = event.detail.value; + this.itemVariants = [...this.itemVariants]; + } + } + } + handleVariantPropertyChange(event) { if (event.currentTarget.dataset.property) { let target = event.currentTarget; @@ -168,13 +293,16 @@ export default class IndicatorBuilder extends LightningElement { newIndicatorVariant(label, whenToDisplay, isActive = true, iconSource = 'sldsIcon') { let whenToDisplayOptions = this.whenToDisplayOptions; + let index = this.itemVariants.length; let newVariant = { label, whenToDisplay, isActive, iconSource, + index, hoverText: '', + overrideColors: false, get iconSourceIs() { return { [this.iconSource]: true } }, @@ -186,14 +314,14 @@ export default class IndicatorBuilder extends LightningElement { return 'slds-vertical-tabs__nav-item' + (this.isActive ? ' slds-is-active' : ''); }, get tabPaneClass() { - return 'slds-vertical-tabs__content ' + (this.isActive ? 'slds-show' : 'slds-hide'); + return 'slds-vertical-tabs__content slds-col ' + (this.isActive ? 'slds-show' : 'slds-hide'); }, - get showColourOption() { + get showColorOption() { return this.iconSourceIs.sldsIcon; }, - get showColourSelectors() { - return this.iconSourceIs.staticText || (this.showColourOption && this.overrideColours); - } + get showColorSelectors() { + return this.iconSourceIs.staticText || (this.showColorOption && this.overrideColors); + } } console.log(`newVariant = ${JSON.stringify(newVariant)}`); return newVariant; diff --git a/force-app/main/default/lwc/indicatorStyleConfig/__tests__/indicatorStyleConfig.test.js b/force-app/main/default/lwc/indicatorStyleConfig/__tests__/indicatorStyleConfig.test.js new file mode 100644 index 0000000..8121db6 --- /dev/null +++ b/force-app/main/default/lwc/indicatorStyleConfig/__tests__/indicatorStyleConfig.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import IndicatorStyleConfig from 'c/indicatorStyleConfig'; + +describe('c-indicator-style-config', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-indicator-style-config', { + is: IndicatorStyleConfig + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.html b/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.html new file mode 100644 index 0000000..0fb9800 --- /dev/null +++ b/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.html @@ -0,0 +1,75 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js b/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js new file mode 100644 index 0000000..ec59e12 --- /dev/null +++ b/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js @@ -0,0 +1,60 @@ +import { LightningElement, api } from 'lwc'; +import { IMAGE_SOURCE_OPTIONS, IMAGE_SIZE_OPTIONS, transformConstantObject } from 'c/indicatorUtils'; + +export default class IndicatorStyleConfig extends LightningElement { + @api + get indicator() { + return this._indicator; + } + set indicator(value) { + this._indicator = value; + } + _indicator = {}; + get indicatorString() { return JSON.stringify(this.indicator) }; + + imageSourceOptions = transformConstantObject(IMAGE_SOURCE_OPTIONS).options; + imageSizeOptions = transformConstantObject(IMAGE_SIZE_OPTIONS).options; + + handleIndicatorPropertyChange(event) { + if (event.currentTarget.dataset.property) { + let target = event.currentTarget; + let tagName = target.tagName.toLowerCase(); + let value; + if (tagName === 'c-icon-selector') { + value = event.detail; + } else if (target.type === 'checkbox') { + value = target.checked; + } else if (tagName === 'lightning-combobox') { + value = event.detail.value; + } else { + value = target.value; + } + + console.log(`value is ${value}, property name is ${target.dataset.property}`); + + const detail = { + index: this.indicator.index, + value: value, + propertyName: target.dataset.property, + } + const selectedEvent = new CustomEvent("indicatorchange", { detail }); + this.dispatchEvent(selectedEvent); + + if (target.dataset.property === 'iconSource') { + const nullSourceEvent = new CustomEvent("indicatorchange", { + detail: { + value: null, + propertyName: 'sourceValue' + } + }); + this.dispatchEvent(nullSourceEvent); + } + + // this.indicator[target.dataset.property] = value; + // if (target.dataset.property === 'iconSource') { + // this.indicator.sourceValue = null; + // } + // console.log(`updated indicator value = ${JSON.stringify(this.indicator)}`); + } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js-meta.xml b/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js-meta.xml new file mode 100644 index 0000000..6127d85 --- /dev/null +++ b/force-app/main/default/lwc/indicatorStyleConfig/indicatorStyleConfig.js-meta.xml @@ -0,0 +1,5 @@ + + + 59.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorUtils/__tests__/indicatorUtils.test.js b/force-app/main/default/lwc/indicatorUtils/__tests__/indicatorUtils.test.js new file mode 100644 index 0000000..283c28f --- /dev/null +++ b/force-app/main/default/lwc/indicatorUtils/__tests__/indicatorUtils.test.js @@ -0,0 +1,25 @@ +import { createElement } from 'lwc'; +import IndicatorUtils from 'c/indicatorUtils'; + +describe('c-indicator-utils', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + it('TODO: test case generated by CLI command, please fill in test logic', () => { + // Arrange + const element = createElement('c-indicator-utils', { + is: IndicatorUtils + }); + + // Act + document.body.appendChild(element); + + // Assert + // const div = element.shadowRoot.querySelector('div'); + expect(1).toBe(1); + }); +}); \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorUtils/indicatorUtils.js b/force-app/main/default/lwc/indicatorUtils/indicatorUtils.js new file mode 100644 index 0000000..275dbcb --- /dev/null +++ b/force-app/main/default/lwc/indicatorUtils/indicatorUtils.js @@ -0,0 +1,31 @@ +const IMAGE_SOURCE_OPTIONS = { + ICON: { label: 'Lightning Icon', value: 'sldsIcon', default: true }, + TEXT: { label: 'Static Text', value: 'staticText' }, + URL: { label: 'URL', value: 'url' }, + STATIC_RESOURCE: { label: 'Static Resource', value: 'staticResource' }, +}; + +const IMAGE_SIZE_OPTIONS = { + X_SMALL: { label: 'x-small', value: 'x-small' }, + SMALL: { label: 'small', value: 'small' }, + MEDIUM: { label: 'medium', value: 'medium', default: true }, + LARGE: { label: 'large', value: 'large' }, +}; + +const transformConstantObject = (constant) => { + return { + list: constant, + get options() { return Object.values(this.list).filter(option => !option.hide); }, + get default() { return this.options.find(option => option.default); }, + findFromValue: function (value) { + let entry = this.options.find(option => option.value == value); + return entry || this.default; + }, + findFromLabel: function (label) { + let entry = this.options.find(option => option.label == label); + return entry || this.default; + } + } +} + +export { IMAGE_SOURCE_OPTIONS, IMAGE_SIZE_OPTIONS, transformConstantObject } \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorUtils/indicatorUtils.js-meta.xml b/force-app/main/default/lwc/indicatorUtils/indicatorUtils.js-meta.xml new file mode 100644 index 0000000..6127d85 --- /dev/null +++ b/force-app/main/default/lwc/indicatorUtils/indicatorUtils.js-meta.xml @@ -0,0 +1,5 @@ + + + 59.0 + false + \ No newline at end of file From 4fd95ceb34b872ac75ad477579fb042c4c92bbf5 Mon Sep 17 00:00:00 2001 From: tschug Date: Wed, 7 Feb 2024 13:15:54 -0500 Subject: [PATCH 09/23] Order getBundles by label --- force-app/main/default/classes/Cmdt.cls | 1 + 1 file changed, 1 insertion(+) diff --git a/force-app/main/default/classes/Cmdt.cls b/force-app/main/default/classes/Cmdt.cls index ff52300..b36d92c 100644 --- a/force-app/main/default/classes/Cmdt.cls +++ b/force-app/main/default/classes/Cmdt.cls @@ -17,6 +17,7 @@ public with sharing class Cmdt { sObject__r.QualifiedApiName, sObject__r.Label FROM Indicator_Bundle__mdt + ORDER BY Label ] ) { setBundle(bundle); } From 3cdf262c478d354ead243679711c0dddff58e455 Mon Sep 17 00:00:00 2001 From: tschug Date: Sun, 18 Feb 2024 14:11:44 -0500 Subject: [PATCH 10/23] Added MetaDeploy step names --- cumulusci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cumulusci.yml b/cumulusci.yml index 6836f35..1695c0f 100644 --- a/cumulusci.yml +++ b/cumulusci.yml @@ -41,6 +41,7 @@ tasks: deploy_sample_indicators: description: Deploys - Sample Indicators + name: Deploy Sample Indicators group: Salesforce Metadata class_path: cumulusci.tasks.salesforce.Deploy options: @@ -48,6 +49,7 @@ tasks: deploy_sample_indicators_layouts: description: Deploys - Sample Indicators Layouts + name: Deploy Page Layouts for Sample Indicators group: Salesforce Metadata class_path: cumulusci.tasks.salesforce.Deploy options: @@ -55,6 +57,7 @@ tasks: deploy_training_indicators: description: Deploys - Example Indicators used for Training + name: Deploy Training Indicators group: Salesforce Metadata class_path: cumulusci.tasks.salesforce.Deploy options: From 2a51dbec238e8e627ffb03122ab6b4d1e1da3fe0 Mon Sep 17 00:00:00 2001 From: tschug Date: Sun, 18 Feb 2024 14:12:11 -0500 Subject: [PATCH 11/23] Updated sample indicator extensions to use Equals operator --- ...ESPACE___Indicator_Bundle.Contact_Contact_Info.md-meta.xml | 2 +- ...r_Item_Extension.Account_Industry_Construction.md-meta.xml | 4 ++++ ...or_Item_Extension.Account_Industry_Electronics.md-meta.xml | 4 ++++ ...dicator_Item_Extension.Account_Industry_Energy.md-meta.xml | 4 ++++ ...or_Item_Extension.Account_Industry_Engineering.md-meta.xml | 4 ++++ ...tor_Item_Extension.Account_Industry_Government.md-meta.xml | 4 ++++ ..._Item_Extension.Account_Industry_Manufacturing.md-meta.xml | 4 ++++ ...tor_Item_Extension.Account_Industry_Technology.md-meta.xml | 4 ++++ ...ator_Item_Extension.Account_Industry_Utilities.md-meta.xml | 4 ++++ ...__Indicator_Item_Extension.Account_Location_CA.md-meta.xml | 4 ++++ ...dicator_Item_Extension.Account_Location_Canada.md-meta.xml | 4 ++++ ...__Indicator_Item_Extension.Account_Location_US.md-meta.xml | 4 ++++ ...r_Item_Extension.Account_Location_UnitedStates.md-meta.xml | 4 ++++ ...__Indicator_Item_Extension.Account_Rating_Cold.md-meta.xml | 4 ++++ ...___Indicator_Item_Extension.Account_Rating_Hot.md-meta.xml | 4 ++++ ...__Indicator_Item_Extension.Account_Rating_Warm.md-meta.xml | 4 ++++ ..._Indicator_Item_Extension.Account_Source_Other.md-meta.xml | 4 ++++ ...Item_Extension.Account_Source_Partner_Referral.md-meta.xml | 4 ++++ ..._Indicator_Item_Extension.Account_Source_Phone.md-meta.xml | 4 ++++ ...r_Item_Extension.Account_Source_Purchased_List.md-meta.xml | 4 ++++ ...___Indicator_Item_Extension.Account_Source_Web.md-meta.xml | 4 ++++ 21 files changed, 81 insertions(+), 1 deletion(-) diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Bundle.Contact_Contact_Info.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Bundle.Contact_Contact_Info.md-meta.xml index 7cd29ca..05fe41e 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Bundle.Contact_Contact_Info.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Bundle.Contact_Contact_Info.md-meta.xml @@ -24,7 +24,7 @@ %%%NAMESPACE%%%Card_Title__c - Contact Key Details + Contact Missing Key Details %%%NAMESPACE%%%Description__c diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Construction.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Construction.md-meta.xml index a654484..0a0973a 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Construction.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Construction.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Electronics.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Electronics.md-meta.xml index 8a7b9c1..6fb88e6 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Electronics.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Electronics.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Energy.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Energy.md-meta.xml index 0105c50..90d2288 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Energy.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Energy.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Engineering.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Engineering.md-meta.xml index 2f6da0a..70ead51 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Engineering.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Engineering.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Government.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Government.md-meta.xml index c0aed00..643b2f6 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Government.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Government.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Manufacturing.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Manufacturing.md-meta.xml index 1aebd33..1c84e65 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Manufacturing.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Manufacturing.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Technology.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Technology.md-meta.xml index 0b70fcc..e5b9746 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Technology.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Technology.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Utilities.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Utilities.md-meta.xml index f6cc55e..4c46343 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Utilities.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Industry_Utilities.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_CA.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_CA.md-meta.xml index 948b177..ac07599 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_CA.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_CA.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c CA + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_Canada.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_Canada.md-meta.xml index 3932cb9..4b3de25 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_Canada.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_Canada.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c CA + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_US.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_US.md-meta.xml index bd7a6f8..90d3b98 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_US.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_US.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c US + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_UnitedStates.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_UnitedStates.md-meta.xml index cad3fda..473aec4 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_UnitedStates.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Location_UnitedStates.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c US + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Cold.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Cold.md-meta.xml index d69538a..8121542 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Cold.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Cold.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Hot.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Hot.md-meta.xml index f90af75..c4ba112 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Hot.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Hot.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Warm.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Warm.md-meta.xml index 2c92953..b22d81c 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Warm.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Rating_Warm.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Other.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Other.md-meta.xml index a8036e5..509ffcc 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Other.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Other.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Partner_Referral.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Partner_Referral.md-meta.xml index efa6a3e..a0b726f 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Partner_Referral.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Partner_Referral.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Phone.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Phone.md-meta.xml index 90ee59d..987e570 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Phone.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Phone.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Purchased_List.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Purchased_List.md-meta.xml index 62d84fb..f6c7d5e 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Purchased_List.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Purchased_List.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + diff --git a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Web.md-meta.xml b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Web.md-meta.xml index 9374a69..c5c174b 100644 --- a/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Web.md-meta.xml +++ b/unpackaged/config/sample_AccountContact/customMetadata/___NAMESPACE___Indicator_Item_Extension.Account_Source_Web.md-meta.xml @@ -54,4 +54,8 @@ %%%NAMESPACE%%%Static_Text__c + + %%%NAMESPACE%%%Text_Operator__c + Equals + From 3ef6623832b5df01e2df7387be1cf5e6f26c805e Mon Sep 17 00:00:00 2001 From: JodieM Date: Tue, 20 Feb 2024 15:50:34 +1100 Subject: [PATCH 12/23] Update README.md Added new documentation links --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f7a0947..2c3f02a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ With Salesforce Indicators, you can visually highlight important data at a glance, making it easy to focus on what matters most. This Custom Metadata driven Lightning Web Component is all about making key details pop, and giving you lightning-quick insights at a glance on your Salesforce records. - Features: * Visualize your data - Display key details in a visually engaging and clutter-free manner, allowing users to quickly understand important information on the record, summarize related records, or highlight exceptions. * Make your data come alive - Add a mix of Salesforce and custom colors to match your branding to create visually appealing indicators for your Lightning pages giving your users a more engaging experience. @@ -14,38 +13,39 @@ Salesforce Indicators is part of the [Salesforce Open Source Commons](https://he ## Latest Release * [Install Salesforce Indicators](https://install.salesforce.org/products/indicators) -* [Release Notes](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Release-Notes) +* [Release Notes](https://sfdo-community-sprints.github.io/indicators-documentation/docs/release-notes/) ## Project Documentation -* Documentation can be found in the repository [Wiki](https://github.com/SFDO-Community/Salesforce-Indicators/wiki). -* Check out the [Cookbook](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Cookbook) to help you build Indicators that work for your org. +* Documentation can be found on our [Documentation Site](https://sfdo-community-sprints.github.io/indicators-documentation/). +* Check out the [Getting Started with Salesforce Indicators](https://sfdo-community-sprints.github.io/indicators-documentation/docs/getting-started/) page to help get started with how to set up Salesforce Indicators in your org. ## Ask Questions and Get Help * Salesforce Indicators is a community built and maintained Salesforce package, please help support this project and share your experiences in the [Trailblazer Community Group](https://trailhead.salesforce.com/trailblazer-community/groups/0F94S000000HEDASA4?tab=discussion). Ask any questions about the Salesforce Indicators project, or the Open Source Commons. -* If you have any enhancements or issue you can [Log an Issue](https://github.com/SFDO-Community/Salesforce-Indicators/issues). +* If you have any enhancements or issue you can [Log an Issue](https://github.com/SFDO-Community/Salesforce-Indicators/issues) ## Vision & Goals * Enhance the current Indicators Bundle Component to improve the experience for Admins and Users. * Complete the documentation with different recipes to help Admins get up and running quickly. * Showcase and review different apps you can use to achieve similar results, and show how you will probably want to use Salesforce Indicators anyway. * Build our planned Components - these components are built on the same Custom Metadata framework and just show the data in different ways: - * A Grid Component to quickly show your users excptions or a checklist of fields on the record. Optionally show field values, a custom message for each field, and if the field has an exception. + * A Grid Component to quickly show your users excptions or a checklist of fields on the record. Optionally show field values, a custom message for each field, and if the field has an exception. * A Panel Component to provide more value and features than the standard record highlights panel horizontally, or a panel that display the key data vertically. # How to Contribute: - [Install Salesforce Indicators](https://install.salesforce.org/products/indicators) -- [Set up the Indicator Bundle](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Indicator-Bundle) +- [Set up Salesforce Indicators](https://sfdo-community-sprints.github.io/indicators-documentation/docs/setup-salesforce-indicators/) - Ask any questions on our [Trailblazer Community Group](https://trailhead.salesforce.com/trailblazer-community/groups/0F94S000000HEDASA4?tab=discussion) -- Add your own Recipes to the [Cookbook](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Cookbook) and -- Add reviews of any [similar or competitor components](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Other-Apps-and-Components-to-Enhance-Your-Org) +- Add your own [Recipes](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Cookbook) to our documentation +- Add reviews of any [similar or competitor components](https://sfdo-community-sprints.github.io/indicators-documentation/docs/components/other-solutions/) - [Volunteer](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/How-to-Volunteer) to enhance the code - [Log an Issue](https://github.com/SFDO-Community/Salesforce-Indicators/issues) - Join us at an upcoming [Salesforce Commons Community Sprint](https://trailhead.salesforce.com/trailblazer-community/groups/0F94S000000GwVK?tab=discussion) ## Project Acomplishments -* Rebuilt the component to support Custom Metadata Types +* Built the component to support Custom Metadata Types * Enhancements to the Indicator Bundle Component * The Indicator Key compnent and Setup components to help build and understand the Indicators easily * New companion components (Grid and Panel) in progress * Packaging and release setup * Marketing and release of Salesforce Indicators +* New UI for building Salesforce Indicators in progress From c4841d90e8a48af63b6c0ffc889f0c6beeba693a Mon Sep 17 00:00:00 2001 From: JodieM Date: Tue, 20 Feb 2024 15:53:05 +1100 Subject: [PATCH 13/23] Update README.md Fixed some links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2c3f02a..7b935af 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Salesforce Indicators is part of the [Salesforce Open Source Commons](https://he ## Ask Questions and Get Help * Salesforce Indicators is a community built and maintained Salesforce package, please help support this project and share your experiences in the [Trailblazer Community Group](https://trailhead.salesforce.com/trailblazer-community/groups/0F94S000000HEDASA4?tab=discussion). Ask any questions about the Salesforce Indicators project, or the Open Source Commons. -* If you have any enhancements or issue you can [Log an Issue](https://github.com/SFDO-Community/Salesforce-Indicators/issues) +* If you have any enhancements or issue you can [Log an Issue](https://github.com/SFDO-Community/Salesforce-Indicators/issues).. ## Vision & Goals * Enhance the current Indicators Bundle Component to improve the experience for Admins and Users. @@ -35,9 +35,9 @@ Salesforce Indicators is part of the [Salesforce Open Source Commons](https://he - [Install Salesforce Indicators](https://install.salesforce.org/products/indicators) - [Set up Salesforce Indicators](https://sfdo-community-sprints.github.io/indicators-documentation/docs/setup-salesforce-indicators/) - Ask any questions on our [Trailblazer Community Group](https://trailhead.salesforce.com/trailblazer-community/groups/0F94S000000HEDASA4?tab=discussion) -- Add your own [Recipes](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/Cookbook) to our documentation +- Add your own [Recipes](https://sfdo-community-sprints.github.io/indicators-documentation/docs/recipes/) to our documentation - Add reviews of any [similar or competitor components](https://sfdo-community-sprints.github.io/indicators-documentation/docs/components/other-solutions/) -- [Volunteer](https://github.com/SFDO-Community/Salesforce-Indicators/wiki/How-to-Volunteer) to enhance the code +- [Volunteer](https://sfdo-community-sprints.github.io/indicators-documentation/docs/getting-involved/how-to-volunteer/) to enhance the app - [Log an Issue](https://github.com/SFDO-Community/Salesforce-Indicators/issues) - Join us at an upcoming [Salesforce Commons Community Sprint](https://trailhead.salesforce.com/trailblazer-community/groups/0F94S000000GwVK?tab=discussion) From 7d3a50686a9d77ffd23c61662be7fff5827c20df Mon Sep 17 00:00:00 2001 From: JodieM Date: Sat, 17 Aug 2024 21:48:07 +1000 Subject: [PATCH 14/23] Extra vertical space between icons --- .../lwc/indicatorBundle/indicatorBundle.html | 2 +- .../indicatorBundleItem.html | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/force-app/main/default/lwc/indicatorBundle/indicatorBundle.html b/force-app/main/default/lwc/indicatorBundle/indicatorBundle.html index 9c4eebd..39f7d97 100644 --- a/force-app/main/default/lwc/indicatorBundle/indicatorBundle.html +++ b/force-app/main/default/lwc/indicatorBundle/indicatorBundle.html @@ -42,7 +42,7 @@

-
+
diff --git a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js index dd13296..ac1c9ba 100644 --- a/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js +++ b/force-app/main/default/lwc/fsc_combobox/fsc_combobox.js @@ -1,6 +1,6 @@ // Style from: https://www.lightningdesignsystem.com/components/combobox import { LightningElement, api, track } from 'lwc'; -import { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } from 'c/fsc_comboboxUtils'; +import { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase, CLEAR_REQUEST_EVENT_NAME } from 'c/fsc_comboboxUtils'; const VARIANTS = { BASE: 'base', @@ -37,6 +37,7 @@ export default class OptionSelector extends LightningElement { @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. @api filterActions = false; // If true, action items will be filtered along with selection items. By default, action items are always visible @api showSelectedCount = false; // If true, when allowMultiselect is true, the component label will show the number of selected values in parentheses + @api notifyOnClear = false; // If true, clicking the clear button will not automatically clear the selection. Instead it will dispatch a notification event so that the parent component can implement any logic before clearing @api hideSelectedValues = false; // Reserved for future use @api builderContext; @@ -175,7 +176,7 @@ export default class OptionSelector extends LightningElement { /* PUBLIC FUNCTIONS */ @api reportValidity() { - if (!this.required || this.selectedOptions.length) { + if (!this.required || this.selectedOptions.length) { this.setCustomValidity(); } else { this.setCustomValidity(this.messageWhenValueMissing); @@ -200,6 +201,11 @@ export default class OptionSelector extends LightningElement { this.errorMessage = errorMessage; } + @api + focus() { + this.onRender.inputFocus = true; + } + /* LIFECYCLE HOOKS */ connectedCallback() { window.addEventListener("resize", () => { this.resizePillContainer() }); @@ -254,7 +260,8 @@ export default class OptionSelector extends LightningElement { } get isInputDisabled() { - return this.disabled || this.isLoading; + // 5/6/2024: Removing isLoading as a disabling factor because it was interfering with the lookup component + return this.disabled;// || this.isLoading; } get noMatchFound() { @@ -278,7 +285,7 @@ export default class OptionSelector extends LightningElement { } get showLabel() { - return this.variant !== VARIANTS.LABEL_HIDDEN; + return this.label && this.variant !== VARIANTS.LABEL_HIDDEN; } /* COMPUTED CSS CLASS STRINGS */ @@ -316,8 +323,9 @@ export default class OptionSelector extends LightningElement { this.showList = false; this.highlightedOptionIndex = undefined; this.numOptionsDisplayed = LOAD_COUNT; - if (this.listboxElement) + if (this.listboxElement) { this.listboxElement.scrollTop = 0; + } } resetSearch() { @@ -363,12 +371,12 @@ export default class OptionSelector extends LightningElement { // console.log('selecting '+ JSON.stringify(selectedOption)); // console.log('value before adding: '+ this.value); // console.log('values before adding: '+ JSON.stringify(this.values) +', length: '+ this.values.length); - if (!selectedOption) { + if (!selectedOption || selectedOption.isGrouping) { return; } if (selectedOption.isAction) { this.dispatchEvent(new CustomEvent('customaction', { detail: selectedOption.value })); - } else { + } else { this.values.push(selectedOption.value); this.values = this.values; // this.values = [...this.values, selectedOption.value]; // using spread instead of values.push to trigger the setter @@ -414,6 +422,13 @@ export default class OptionSelector extends LightningElement { } } + @api + clearSelection() { + this.values = []; + this.dispatchOptions(); + this.openList(); + } + highlightOption(index) { this.highlightedOptionIndex = index; this.onRender.highlightOption = true; @@ -515,11 +530,23 @@ export default class OptionSelector extends LightningElement { this.highlightedOptionIndex = undefined; } - handleClearClick() { + handleClearClick(event) { + // I don't know why, but without the preventDefault/stopPropagation, clicking this button sometimes passed URL parameters to the page with refreshed the page + event.preventDefault(); + event.stopPropagation(); if (!this.disabled) { - this.values = []; - this.dispatchOptions(); - this.openList(); + if (this.notifyOnClear) { + this.dispatchEvent(new CustomEvent(CLEAR_REQUEST_EVENT_NAME)); + /* + this.dispatchEvent(new CustomEvent( + 'clearrequest', + // { bubbles: true, } + { bubbles: true, composed: true } + )); + */ + } else { + this.clearSelection(); + } } } diff --git a/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js index 7af1721..b6efa8b 100644 --- a/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js +++ b/force-app/main/default/lwc/fsc_comboboxUtils/fsc_comboboxUtils.js @@ -5,6 +5,8 @@ const KEYS = { ENTER: 'Enter' } +const CLEAR_REQUEST_EVENT_NAME = 'clearrequest'; + const setValuesFromMultipleInput = (values) => { if (!values) { return []; @@ -27,7 +29,6 @@ const includesIgnoreCase = (valueToSearch, valueToSearchFor) => { } else { return valueToSearch.toLowerCase().includes(valueToSearchFor.toLowerCase()); } - } -export { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } \ No newline at end of file +export { KEYS, setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase, CLEAR_REQUEST_EVENT_NAME } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html index 32589e5..dba7d6c 100644 --- a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.html @@ -21,5 +21,7 @@ field-level-help={fieldLevelHelp} error-message={errorMessage} builder-context={builderContext} + notify-on-clear={notifyOnClear} + onclearrequest={handleClearRequest} > \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js index de655bf..169b622 100644 --- a/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js +++ b/force-app/main/default/lwc/fsc_fieldSelector2/fsc_fieldSelector2.js @@ -2,7 +2,9 @@ import { LightningElement, api, track, wire } from 'lwc'; import { getObjectInfo } from 'lightning/uiObjectInfoApi'; import getObjectFields from '@salesforce/apex/ObjectFieldSelectorController.getObjectFields'; import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; -import { setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase } from 'c/fsc_comboboxUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput, includesIgnoreCase, CLEAR_REQUEST_EVENT_NAME } from 'c/fsc_comboboxUtils'; + +const COMBOBOX_COMPONENT_NAME = 'c-fsc_combobox'; const DATA_TYPE_ICONS = { Address: 'utility:location', @@ -45,11 +47,9 @@ export default class Fsc_fieldSelector2 extends LightningElement { @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. -<<<<<<< HEAD - @api allowReferenceLookups = false; -======= @api allowReferenceLookups = false; ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + @api defaultToNameField = false; + @api notifyOnClear = false; @track fields = []; @track _values = []; @track _availableFieldTypes = []; @@ -122,13 +122,17 @@ export default class Fsc_fieldSelector2 extends LightningElement { @api reportValidity() { - return this.template.querySelector('c-fsc_combobox').reportValidity(); + return this.combobox.reportValidity(); } @api validate() { - // console.log('in fieldSelector validate, returning '+ JSON.stringify(this.template.querySelector('c-fsc_combobox').validate())); - return this.template.querySelector('c-fsc_combobox').validate(); + return this.combobox.validate(); + } + + @api + clearSelection() { + this.combobox.clearSelection(); } get isLoadingOrDisabled() { @@ -145,6 +149,10 @@ export default class Fsc_fieldSelector2 extends LightningElement { } } + get combobox() { + return this.template.querySelector(COMBOBOX_COMPONENT_NAME); + } + @wire(getObjectInfo, { objectApiName: '$objectName' }) handleGetObjectInfo({ error, data }) { if (error) { @@ -160,10 +168,10 @@ export default class Fsc_fieldSelector2 extends LightningElement { } } } else if (data) { - console.log(JSON.stringify(Object.values(data.fields).filter(field => field.relationshipName)[0])); + // console.log(JSON.stringify(Object.values(data.fields).filter(field => field.relationshipName)[0])); this.processFields(Object.values(data.fields)); } else { - console.log('neither data nor error'); + // console.log('neither data nor error'); } this.isLoading = false; } @@ -195,6 +203,10 @@ export default class Fsc_fieldSelector2 extends LightningElement { this.dispatchFields(); } + handleClearRequest() { + this.dispatchEvent(new CustomEvent(CLEAR_REQUEST_EVENT_NAME)); + } + /* ACTION FUNCTIONS */ processFields(fields) { if (this.availableFieldTypes?.length) { @@ -203,14 +215,18 @@ export default class Fsc_fieldSelector2 extends LightningElement { fields = fields.filter(field => !field.referenceToInfos.length || field.referenceToInfos.some(ref => includesIgnoreCase(this.availableReferenceTypes, ref.apiName))); } } -<<<<<<< HEAD - this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, field.dataType, this.hideIcons ? null : this.getIconFromDataType(field.dataType))); -======= - this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, this.hideIcons ? null : this.getIconFromDataType(field.dataType))); ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + this.fields = fields.map(field => this.newField(field.label, field.apiName, field.apiName, this.hideIcons ? null : this.getIconFromDataType(field.dataType), field.nameField)); this.fields.sort((a, b) => { return a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1; }); + if (this.defaultToNameField && !this.value) { + // First check to see if "Name" is a valid name field, as some objects like Contact have multiple name fields + let nameField = this.fields.find(field => field.value === 'Name' && field.nameField) || this.fields.find(field => field.nameField); + if (nameField) { + this.value = nameField.value; + this.dispatchFields(); + } + } } @@ -224,29 +240,12 @@ export default class Fsc_fieldSelector2 extends LightningElement { } dispatchFields() { -<<<<<<< HEAD - let fieldData; - if (this.values.length) { - fieldData = this.fields.filter(field => this.values.includes(field.value)); - // { - // return this.values.find(value => field.apiName == value) - // }); - } - let detail = { - value: this.value, - values: this.values, - fieldData: fieldData - } - this.dispatchEvent(new CustomEvent('change', { detail })); - } -======= let detail = { value: this.value, values: this.values, } this.dispatchEvent(new CustomEvent('change', { detail })); } ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef /* UTILITY FUNCTIONS */ getIconFromDataType(type) { @@ -254,12 +253,7 @@ export default class Fsc_fieldSelector2 extends LightningElement { return matchingType?.icon || DEFAULT_ICON; } -<<<<<<< HEAD - newField(label, sublabel, value, dataType, icon) { - return { label, sublabel, value, dataType, icon } -======= - newField(label, sublabel, value, icon) { - return { label, sublabel, value, icon } ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + newField(label, sublabel, value, icon, nameField) { + return { label, sublabel, value, icon, nameField }; } } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html index e84150f..360c589 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.html @@ -9,8 +9,9 @@
@@ -19,12 +20,9 @@ -======= - builder-context={builderContext}> ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + default-to-name-field={defaultToNameField} disabled={fieldPicklistIsDisabled} + onchange={handleFieldChange} value={fieldValue} builder-context={builderContext} notify-on-clear + onclearrequest={handleFieldClearRequest}>
diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js index c2cb002..8d8cc69 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js @@ -1,15 +1,11 @@ import { LightningElement, api, track } from 'lwc'; -import { FlowAttributeChangeEvent } from 'lightning/flowSupport'; +// import { FlowAttributeChangeEvent } from 'lightning/flowSupport'; import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_comboboxUtils'; export default class Fsc_objectFieldSelector extends LightningElement { availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); -<<<<<<< HEAD - displayTypeOptions = transformConstantObject(DISPLAY_TYPE_OPTIONS); -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef @api name; @api masterLabel; @@ -17,30 +13,24 @@ export default class Fsc_objectFieldSelector extends LightningElement { @api fieldLabel = 'Select Field'; @api valueDelimiter = ','; + @api disabled; @api disableObjectPicklist = false; + @api disableFieldPicklist = false; @api hideObjectPicklist = false; @api hideFieldPicklist = false; @api objectAllowMultiselect = false; @api fieldAllowMultiselect = false; -<<<<<<< HEAD - @api allowReferenceLookups = false; -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef @api required = false; + @api notifyOnClear = false; @api availableObjectSelection = this.availableObjectOptions.default?.value; @api availableObjects; @api availableFieldTypes; @api availableReferenceTypes; - @api lockDefaultObject; + // @api lockDefaultObject; Redundant, same as disableObjectPicklist @api defaultToNameField; @api layout = LAYOUT_OPTIONS.VERTICAL.value; -<<<<<<< HEAD - @track fieldData; // used to retain all data from each seleted field, such as field data type - -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef @api get builderContext() { return this._builderContext; @@ -66,11 +56,6 @@ export default class Fsc_objectFieldSelector extends LightningElement { return this.objectValues.join(this.valueDelimiter); } set objectValue(value) { -<<<<<<< HEAD -======= - console.log('in set objectValue'); - console.log(value); ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef this.objectValues = setValuesFromSingularInput(value, this.valueDelimiter, this.objectAllowMultiselect); } @@ -105,10 +90,6 @@ export default class Fsc_objectFieldSelector extends LightningElement { this.hideFieldPicklist = true; } } -<<<<<<< HEAD - _displayType = this.displayTypeOptions.default?.value; -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef @api reportValidity() { @@ -137,11 +118,7 @@ export default class Fsc_objectFieldSelector extends LightningElement { // if (this.fieldSelector && this.fieldSelector.validate().errorMessage) { // errorMessages.push(this.fieldSelector.validate().errorMessage) // } -<<<<<<< HEAD - // console.log('in ofsValidate, errorMessages = ' + errorMessages); -======= console.log('in ofsValidate, errorMessages = ' + errorMessages); ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef if (errorMessages.length) { return { isValid: false, @@ -152,6 +129,16 @@ export default class Fsc_objectFieldSelector extends LightningElement { } } + @api + clearFieldSelection() { + this.fieldSelector.clearSelection(); + } + + @api + clearObjectSelection() { + this.objectSelector.clearSelection(); + } + get computedColClass() { let classString = 'slds-col'; if (this.displayType === DISPLAY_TYPE_OPTIONS.BOTH.value && this.layout === LAYOUT_OPTIONS.HORIZONTAL.value) { @@ -170,46 +157,52 @@ export default class Fsc_objectFieldSelector extends LightningElement { return this.template.querySelector('c-fsc_field-selector2'); } + get objectPicklistIsDisabled() { + return this.disableObjectPicklist || this.disabled; + } + + get fieldPicklistIsDisabled() { + return this.disableFieldPicklist || this.disabled; + } + handleObjectChange(event) { this.objectValue = event.detail.value; - const attributeChangeEvent = new FlowAttributeChangeEvent( - 'objectValue', - this.objectValue - ); - this.dispatchEvent(attributeChangeEvent); + // const attributeChangeEvent = new FlowAttributeChangeEvent( + // 'objectValue', + // this.objectValue + // ); + // this.dispatchEvent(attributeChangeEvent); this.dispatchValues(); } handleFieldChange(event) { this.fieldValue = event.detail.value; -<<<<<<< HEAD - this.fieldData = event.detail.fieldData; - // console.log(`fieldData = ${JSON.stringify(this.fieldData)}`); -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef - const attributeChangeEvent = new FlowAttributeChangeEvent( - 'fieldValue', - this.fieldValue - ); - this.dispatchEvent(attributeChangeEvent); + // const attributeChangeEvent = new FlowAttributeChangeEvent( + // 'fieldValue', + // this.fieldValue + // ); + // this.dispatchEvent(attributeChangeEvent); this.dispatchValues(); } + handleFieldClearRequest() { + console.log(`in objectFieldSelector handleFieldClearRequest`); + this.dispatchEvent(new CustomEvent('fieldclearrequest')); + } + + handleObjectClearRequest() { + console.log(`in objectFieldSelector handleObjectClearRequest`); + this.dispatchEvent(new CustomEvent('objectclearrequest')); + } + dispatchValues() { - this.dispatchEvent(new CustomEvent('change', { - detail: { - objectValue: this.objectValue, - objectValues: this.objectValues, - fieldValue: this.fieldValue, -<<<<<<< HEAD - fieldValues: this.fieldValues, - fieldData: this.fieldData - -======= - fieldValues: this.fieldValues ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef - } - })); + let detail = { + objectValue: this.objectValue, + objectValues: this.objectValues, + fieldValue: this.fieldValue, + fieldValues: this.fieldValues + } + this.dispatchEvent(new CustomEvent('change', { detail })); } diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml index 69ac572..dffefe2 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js-meta.xml @@ -3,15 +3,11 @@ 54.0 true Object and Field Selector - + ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef - + @@ -29,7 +25,6 @@ - - + --> \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html index 6d62dd2..735c69a 100644 --- a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html @@ -20,5 +20,8 @@ icon-size="x-small" field-level-help={fieldLevelHelp} builder-context={builderContext} - variant={variant}> + variant={variant} + notify-on-clear={notifyOnClear} + onclearrequest={handleClearRequest} + > \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js index 172bf36..a0c061f 100644 --- a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js @@ -1,9 +1,10 @@ import { LightningElement, wire, track, api } from 'lwc'; import getObjects from '@salesforce/apex/ObjectFieldSelectorController.getObjects'; import { DISPLAY_TYPE_OPTIONS, AVAILABLE_OBJECT_OPTIONS, FIELD_TYPES, LAYOUT_OPTIONS, transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; -import { setValuesFromMultipleInput, setValuesFromSingularInput } from 'c/fsc_comboboxUtils'; +import { setValuesFromMultipleInput, setValuesFromSingularInput, CLEAR_REQUEST_EVENT_NAME } from 'c/fsc_comboboxUtils'; const ANCILLARY_SUFFIXES = ['Feed', 'Tag', 'Share', 'ChangeEvent', 'History']; +const COMBOBOX_COMPONENT_NAME = 'c-fsc_combobox'; export default class Fsc_objectSelector extends LightningElement { availableObjectOptions = transformConstantObject(AVAILABLE_OBJECT_OPTIONS); @@ -24,6 +25,7 @@ export default class Fsc_objectSelector extends LightningElement { @api hidePills = false; // If true, list of selected pills in multiselect mode will not be displayed (generally because a parent component wants to display them differently). @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. + @api notifyOnClear = false; // @api availableObjectSelection = this.availableObjectOptions.default?.value; @api availableObjects = []; @@ -55,7 +57,7 @@ export default class Fsc_objectSelector extends LightningElement { return this._availableObjectSelection; } set availableObjectSelection(value) { - console.log(' in set availableObjectSelection to ' + value); + // console.log(' in set availableObjectSelection to ' + value); this._availableObjectSelection = value; if (this.hasConnected && this.values.length) { this.values = []; @@ -81,6 +83,10 @@ export default class Fsc_objectSelector extends LightningElement { return this.isLoading ? 'Loading...' : this.placeholder; } + get combobox() { + return this.template.querySelector(COMBOBOX_COMPONENT_NAME); + } + // @api // get availableObjects() { // return this._availableObjects; @@ -107,28 +113,36 @@ export default class Fsc_objectSelector extends LightningElement { } loadObjectCategory(category) { - if (!this.value) { - this.isLoading = true; - } + // if (!this.value) { + // this.isLoading = true; + // } getObjects({ selectionType: category }) .then(result => { this.addObjectOptions(result.objects, category); - this.isLoading = false; + if (!this.value || this.objectOptions.find(option => option.value == this.value)) { + this.isLoading = false; + } }); } @api reportValidity() { - return this.template.querySelector('c-fsc_combobox').reportValidity(); + return this.combobox.reportValidity(); } @api validate() { - return this.template.querySelector('c-fsc_combobox').validate(); + return this.combobox.validate(); + } + + @api + clearSelection() { + this.combobox.clearSelection(); } connectedCallback() { this.hasConnected = true; + this.isLoading = true; let initialLoadCategories = [AVAILABLE_OBJECT_OPTIONS.STANDARD.value, AVAILABLE_OBJECT_OPTIONS.CUSTOM.value, AVAILABLE_OBJECT_OPTIONS.ANCILLARY.value]; initialLoadCategories.forEach(category => { this.loadObjectCategory(category); @@ -140,12 +154,16 @@ export default class Fsc_objectSelector extends LightningElement { this.dispatchObjects(); } + handleClearRequest() { + console.log(`in objectSelector handleClearRequest`); + this.dispatchEvent(new CustomEvent(CLEAR_REQUEST_EVENT_NAME)); + } + dispatchObjects() { let detail = { value: this.value, values: this.values, } - console.log('dispatching objects', JSON.stringify(detail)); this.dispatchEvent(new CustomEvent('change', { detail })); } diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css index e0f8947..343bc4e 100644 --- a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.css @@ -1,7 +1,18 @@ -.slds-vertical-tabs, .slds-vertical-tabs * { +/* .slds-vertical-tabs, .slds-vertical-tabs * { */ + /* overflow: visible; */ +/* } */ +/* , .slds-vertical-tabs__content, .slds-vertical-tabs__content * { */ +.slds-vertical-tabs { overflow: visible; } -.slds-vertical-tabs__content{ - overflow: visible; +.deleteVariantButton { + position: absolute; + right: 0.25em; + opacity: 0; + transition: 0.15s ease-in-out; +} + +.tabLink:hover .deleteVariantButton { + opacity: 1; } \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html index e9f1bc4..07bf79c 100644 --- a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html @@ -5,283 +5,230 @@

Indicator Builder

-
-
- -
-
- -
-
- -
-
-<<<<<<< HEAD - - +
+
+
+ +
+
+ +
+
+ +
+
+ +
- - -
+ + + ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef \ No newline at end of file diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js index 0f9de81..c0c91a5 100644 --- a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.js @@ -1,69 +1,28 @@ -<<<<<<< HEAD -import { LightningElement, api, track, wire } from 'lwc'; -import { /* FIELD_TYPES ,*/ transformConstantObject } from 'c/fsc_objectFieldSelectorUtils'; -import { getObjectInfo } from "lightning/uiObjectInfoApi"; +// TODO: set "display logic" to only show appropriate filters based on field type +// TODO: incorporate all data from saved Indicator Item metadata +// TODO: fix lag on combobox load +// TODO: add re-ordering of variants (drag/drop or arrows) -const FIELD_TYPES = { - TEXT: { value: 'text', default: true }, - NUMBER: { value: 'number', dataTypes: ['Integer', 'Double', 'Int', 'Long'] }, - DATE: { value: 'date', dataTypes: ['DateTime', 'Date', 'Time'] }, -} - -const SHOW_ONE_OR_ALL = { - SHOW_ONE: { label: 'the first variant with matching criteria', value: 'showOne', default: true }, - SHOW_ALL: { label: 'all variants with matching criteria', value: 'showAll' } +import { LightningElement, api, track } from 'lwc'; +// Icons last updated 9/24/2024 +const ICONS = { + utility: 'activity,ad_set,add_above,add_below,add_source,add,adduser,adjust_value,advanced_function,advertising,agent_home,agent_session,aggregate,aggregation_policy,alert,all,anchor,angle,animal_and_nature,announcement,answer,answered_twice,anywhere_alert,anywhere_chat,apex_alt,apex_plugin,apex,app_web_messaging,approval,apps,archive,array,arrow_bottom,arrow_left,arrow_right,arrow_top,arrowdown,arrowup,asset_audit,asset_object,asset_repossessed,asset_warranty,assignment,attach,automate,away,back,ban,block_visitor,bold,bookmark_alt,bookmark_stroke,bookmark,bottom_align,bottom_group_alignment,breadcrumbs,broadcast,brush,bucket,budget_category_value,budget_period,bug,builder,bundle_config,bundle_policy,button_choice,buyer_group_qualifier,calculated_insights,call,campaign,cancel_file_request,cancel_transfer,cant_sync,capacity_plan,capslock,captions,card_details,cart,case,cases,center_align_text,center_align,center_group_alignment,change_owner,change_record_type,change_request,chart,chat,check,checkin,checkout,chevrondown,chevronleft,chevronright,chevronup,choice,circle,classic_interface,clear,clock,close,cms,collapse_all,collection_alt,collection_variable,collection,color_swatch,columns,comments,company,component_customization,connected_apps,constant,contact_request,contact,contactless_pay,contract_alt,contract_doc,contract_line_outcome_data,contract_line_outcome,contract_payment,contract,copy_to_clipboard,copy,coupon_codes,crossfilter,currency_input,currency,custom_apps,customer_workspace,customer,cut,dash,data_cloud,data_graph,data_mapping,data_model,data_transforms,database,datadotcom,date_input,date_time,dayview,delete,deprecate,description,desktop_and_phone,desktop_console,desktop,detach,dialing,diamond,discounts,dislike,display_rich_text,display_text,dock_panel,document_preview,down,download,drag_and_drop,drag,duration_downscale,dynamic_record_choice,edit_form,edit_gpt,edit,education,einstein_alt,einstein,email_open,email,emoji,end_call,end_chat,end_messaging_session,engage,enter,entitlement,erect_window,error,event_ext,event,events,expand_all,expand_alt,expand,expired,fallback,favorite_alt,favorite,feed,field_sales,file,filter_criteria_rule,filter_criteria,filter,filterList,flow_alt,flow,food_and_drink,form,format,formula,forward_up,forward,freeze_column,frozen,fulfillment_order,full_width_view,fully_synced,funding_award_adjustment,funding_requirement,global_constant,graph,groups,guidance,hazmat_equipment,heart,height,help_center,help_doc_ext,help,hide_mobile,hide,hierarchy,high_velocity_sales,highlight,holiday_operating_hours,home,hourglass,http,identity,image,in_app_assistant,inbox,incident,incoming_call,indicator_performance_period,info_alt,info,inner_join,insert_tag_field,insert_template,inspector_panel,integration,internal_share,italic,join,jump_to_bottom,jump_to_left,jump_to_right,jump_to_top,justify_text,kanban,key_dates,key,keyboard_dismiss,keypad,knowledge_base,knowledge_smart_link,label,labels,layers,layout_banner,layout_card,layout_overlap,layout_tile,layout,lead,leave_conference,left_align_text,left_align,left_join,left,level_down,level_up,light_bulb,lightning_extension,lightning_inspector,like,line_chart,link,linked,list,listen,live_message,location_permit,location,lock,locked_with_additions,locker_service_api_viewer,locker_service_console,log_a_call,logout,loop,lower_flag,macros,magicwand,maintenance_plan,mark_all_as_read,market,matrix,meet_content_source,meet_focus_content,meet_focus_equal,meet_focus_presenter,meet_present_panel,merge_field,merge,metrics,middle_align,minimize_window,missed_call,mixed_sources_mapping,money,moneybag,monthlyview,more,move,mulesoft,multi_picklist,multi_select_checkbox,muted,new_direct_message,new_window,new,news,no_return,not_in_sync,not_saved,note,notebook,notification_off,notification_snoozed,notification,number_input,office365,offline_briefcase,offline_cached,offline,omni_channel,open_folder,open,opened_folder,opportunity,orchestrator,orders,org_chart,outbound_call,outcome,outer_join,output,overflow,package_org_beta,package_org,package,page_structure,page,palette,password,paste,path_experiment,pause_alt,pause,payment_deferred,payment_gateway,pdf_ext,people,percent,phone_landscape,phone_portrait,photo,picklist_choice,picklist_type,picklist,pin,pinned,plane,planning_poker,play,podcast_webinar,pop_in,power,preview,price_book_entries,price_books,pricing_workspace,print,priority,privately_shared,problem,process,product_consumed_state,product_quantity_rules,product_service_campaign_item,product_service_campaign,product_transfer_state,product_transfer,product_warranty_term,product_workspace,product,products,profile_alt,profile,program_cohort_member,program_cohort,promotion_segments,promotion_tiers,promotions_workspace,promotions,prompt_builder,prompt_edit,prompt,propagation_policy,proposition,push,puzzle,qualifications,question_mark,question,questions_and_answers,queue,quick_text,quip,quotation_marks,quote,radio_button,rating,real_time,reassign,recipe,record_alt,record_collection,record_consent,record_create,record_delete,record_lookup,record_update,record,recurring_exception,recycle_bin_empty,recycle_bin_full,redo,refresh,relate,reminder,remove_formatting,remove_link,replace,replay,reply_all,reply,report_issue,reset_password,resource_absence,resource_capacity,resource_territory,restriction_policy,retail_execution,retweet,ribbon,richtextbulletedlist,richtextindent,richtextnumberedlist,richtextoutdent,right_align_text,right_align,right_join,right,robot,rotate,routing_offline,rows,rules,salesforce_page,salesforce1,save,scan,screen,search,section,segments,send_log,send,sender_email,sentiment_negative,sentiment_neutral,serialized_product_transaction,serialized_product,service_appointment,service_contract,service_report,service_territory_policy,settings,setup_assistant_guide,setup_modal,setup,share_file,share_mobile,share_post,share,shield,shift_pattern_entry,shift_pattern,shift_scheduling_operation,shift_ui,shopping_bag,shortcuts,side_list,signature,signpost,skill,skip_back,skip_forward,skip,slack_conversations,slack,slider,smiley_and_people,sms,snippet,sobject_collection,sobject,socialshare,sort_ascending,sort_policy,sort,spacer,sparkle,sparkles,spinner,stage_collection,stage,standard_objects,steps,stop,store,strategy,strikethrough,success,summary,summarydetail,survey,swarm_request,swarm_session,switch,symbols,sync_in_progress,sync,system_and_global_variable,table_settings,table,tableau,tablet_landscape,tablet_portrait,tabset,talent_development,target_mode,target,task,tax_policy,tax_rate,tax_treatment,text_background_color,text_color,text_template,text,textarea,textbox,threedots_vertical,threedots,thunder,tile_card_list,toggle_off,toggle_on,toggle_panel_bottom,toggle_panel_left,toggle_panel_right,toggle_panel_top,toggle,tollways,top_align,top_group_alignment,topic,topic2,touch_action,tour_check,tour,tracker,trail,trailblazer_ext,trailhead_alt,trailhead_ext,trailhead,transparent,transport_bicycle,transport_heavy_truck,transport_light_truck,transport_walking,travel_and_places,trending,truck,turn_off_notifications,type_tool,type,undelete,undeprecate,underline,undo,unlinked,unlock,unmuted,up,upload,user_role,user,variable,variation_attribute_setup,variation_products,video_off,video,visibility_rule_assigned,voicemail_drop,volume_high,volume_low,volume_off,waits,walkthroughs,warning,warranty_term,watchlist,water,weeklyview,wellness,width,wifi,work_forecast,work_order_type,work_queue,workforce_engagement,world,your_account,yubi_key,zoomin,zoomout', + doctype: 'ai,attachment,audio,box_notes,csv,eps,excel,exe,flash,folder,gdoc,gdocs,gform,gpres,gsheet,html,image,keynote,library_folder,link,mp4,overlay,pack,pages,pdf,ppt,psd,quip_doc,quip_sheet,quip_slide,rtf,shared_folder,slide,stypi,txt,unknown,video,visio,webex,word,xml,zip', + standard: 'account_info,account_score,account,action_list_component,actions_and_buttons,activation_target,activations,address,agent_home,agent_session,aggregate,aggregation_policy,ai_accelerator_card,all,announcement,answer_best,answer_private,answer_public,apex_plugin,apex,app_form_participant,app_form_product_participant,app,approval,apps_admin,apps,article,asset_action_source,asset_action,asset_audit,asset_downtime_period,asset_hierarchy,asset_object,asset_relationship,asset_state_period,asset_warranty,assigned_resource,assignment,attach,attribute_based_pricing,avatar_loading,avatar,bill_of_materials,bot_training,bot,branch_merge,brand,budget_allocation,budget_category_value,budget_period,budget,bundle_config,bundle_policy,bundles_pricing,business_hours,buyer_account,buyer_group_qualifier,buyer_group,calculated_insights,calibration,call_coaching,call_history,call,campaign_members,campaign,cancel_checkout,canvas,capacity_plan,care_request_reviewer,carousel,case_change_status,case_comment,case_email,case_log_a_call,case_milestone,case_transcript,case_wrap_up,case,catalog,category,change_request,channel_program_history,channel_program_levels,channel_program_members,channel_programs,chart,checkout,choice,client,cms,coaching,code_playground,code_set_bundle,code_set,collection_variable,collection,connect_wallet,connected_apps,constant,contact_list,contact_request,contact,contract_line_item,contract_line_outcome_data,contract_line_outcome,contract_payment,contract,cost_model,coupon_codes,crypto_category_wallet_group,crypto_product_category_wallet_role,crypto_product,crypto_transaction_envelope_change_snapshot,crypto_transaction_envelope_item,crypto_transaction_envelope,crypto_transaction,crypto_wallet_group_item,crypto_wallet_group,crypto_wallet,currency_input,currency,custody_chain_entry,custody_entry_verification,custody_override,custom_component_task,custom_notification,custom,customer_360,customer_lifecycle_analytics,customer_portal_users,customer_workspace,customer,customers,dashboard_component,dashboard_ea,dashboard,data_cloud,data_governance,data_graph,data_integration_hub,data_lake_objects,data_mapping,data_model,data_streams,data_transforms,datadotcom,dataset,datashare_target,datashares,date_input,date_time,decision,default,delegated_account,device,digital_verification_config_group,digital_verification_config,disclosure_and_compliance,discounts,display_rich_text,display_text,document_preview,document_reference,document,drafts,duration_downscale,dynamic_highlights_panel,dynamic_record_choice,education,einstein_replies,email_chatter,email,employee_asset,employee_contact,employee_job_position,employee_job,employee_organization,employee,empty,endorsement,entitlement_policy,entitlement_process,entitlement_template,entitlement,entity_milestone,entity,environment_hub,event,events,expense_report_entry,expense_report,expense,facility_bed,feed,feedback,field_sales,file,filter_criteria_rule,filter_criteria,filter,first_non_empty,flow,folder,forecasts,form,formula,fulfillment_order,funding_award_adjustment,funding_requirement,generic_loading,global_constant,goals,group_loading,groups,guidance_center,header_discounts,hierarchy,high_velocity_sales,historical_adherence,holiday_operating_hours,home,household,identifier,immunization,impact_outcome,impact_strategy_assignment,impact_strategy,inbox,incident,indicator_assignment,indicator_definition,indicator_performance_period,indicator_result,individual,insights,instore_locations,investment_account,invocable_action,iot_context,iot_orchestrations,javascript_button,job_family,job_position,job_profile,kanban,key_dates,knowledge,labels,lead_insights,lead_list,lead,learner_program,letterhead,lightning_component,lightning_usage,link,linked,list_email,list_fee,list_rate,live_chat_visitor,live_chat,location_permit,location,log_a_call,logging,loop,macros,maintenance_asset,maintenance_plan,maintenance_work_rule,manual_discounts,market,marketing_actions,med_rec_recommendation,med_rec_statement_recommendation,medication_dispense,medication_ingredient,medication_reconciliation,medication_statement,medication,merge,messaging_conversation,messaging_session,messaging_user,metric_definition,metric,metrics,mulesoft,multi_picklist,multi_select_checkbox,network_contract,news,nft_settings,nft_studio,no_code_model,note,number_input,observation_component,omni_channel,omni_supervisor,operating_hours,operation_plan_execution,operation_plan_request,operation_plan_step_execution,operation_plan_step,operation_plan,opportunity_contact_role,opportunity_splits,opportunity,orchestrator,order_item,orders,outcome_activity,outcome,output,panel_detail,partner_fund_allocation,partner_fund_claim,partner_fund_request,partner_marketing_budget,partners,party_profile,password,past_chat,path_experiment,patient_medication_dosage,payment_gateway,people_score,people,performance,person_account,person_language,person_name,photo,picklist_choice,picklist_type,planogram,policy,poll,portal_roles_and_subordinates,portal_roles,portal,post,practitioner_role,prep_flow,price_adjustment_matrix,price_adjustment_schedule,price_adjustment_tier,price_book_entries,price_books,price_sheet,pricebook,pricing_workspace,problem,procedure_detail,procedure,process_exception,process,product_consumed_state,product_consumed,product_item_transaction,product_item,product_quantity_rules,product_request_line_item,product_request,product_required,product_service_campaign_item,product_service_campaign,product_transfer_state,product_transfer,product_warranty_term,product_workspace,product,products,program_cohort_member,program_cohort,promotion_segments,promotion_tiers,promotions_workspace,promotions,prompt_builder,prompt,propagation_policy,proposition,qualifications,query_editor,question_best,question_feed,queue,quick_text,quip_sheet,quip,quotes,radio_button,rate_adjustment,read_receipts,real_time,recent,recipe,record_consent,record_create,record_delete,record_lookup,record_signature_task,record_update,record,recycle_bin,registered_model,related_list,relationship,repeaters,reply_text,report_type,report,resource_absence,resource_capacity,resource_preference,resource_skill,restriction_policy,return_order_line_item,return_order,reward,robot,rtc_presence,sales_cadence_target,sales_cadence,sales_channel,sales_path,sales_value,salesforce_cms,scan_card,schedule_objective,scheduling_constraint,scheduling_policy,scheduling_workspace_territory,scheduling_workspace,screen,search,section,segments,selling_model,serialized_product_transaction,serialized_product,service_appointment_capacity_usage,service_appointment,service_contract,service_crew_member,service_crew,service_report,service_request_detail,service_request,service_resource,service_territory_location,service_territory_member,service_territory_policy,service_territory,settings,setup_modal,shift_pattern_entry,shift_pattern,shift_preference,shift_scheduling_operation,shift_template,shift_type,shift,shipment,skill_entity,skill_requirement,skill,slack_conversations,slack,slider,sms,snippet_alt,snippet,snippets,sobject_collection,sobject,social,solution,sort_policy,sort,sossession,stage_collection,stage,steps,store_group,store,story,strategy,survey,swarm_request,swarm_session,system_and_global_variable,tableau,task,task2,tax_policy,tax_rate,tax_treatment,taxonomy,team_member,template,text_template,text,textarea,textbox,thanks_loading,thanks,time_period,timesheet_entry,timesheet,timeslot,title_party,today,toggle,topic,topic2,tour_check,tour,trailhead_alt,trailhead,travel_mode,unified_health_score,unmatched,uploaded_model,user_role,user,variable,variation_attribute_setup,variation_products,video,visit_templates,visits,visualforce_page,visualization,voice_call,volume_discounts,waits,walkthroughs,warranty_term,water,webcart,whatsapp,work_capacity_limit,work_capacity_usage,work_contract,work_forecast,work_order_item,work_order,work_plan_rule,work_plan_template_entry,work_plan_template,work_plan,work_queue,work_step_template,work_step,work_summary,work_type_group,work_type,workforce_engagement,workspace,your_account', + custom: 'custom1,custom2,custom3,custom4,custom5,custom6,custom7,custom8,custom9,custom10,custom11,custom12,custom13,custom14,custom15,custom16,custom17,custom18,custom19,custom20,custom21,custom22,custom23,custom24,custom25,custom26,custom27,custom28,custom29,custom30,custom31,custom32,custom33,custom34,custom35,custom36,custom37,custom38,custom39,custom40,custom41,custom42,custom43,custom44,custom45,custom46,custom47,custom48,custom49,custom50,custom51,custom52,custom53,custom54,custom55,custom56,custom57,custom58,custom59,custom60,custom61,custom62,custom63,custom64,custom65,custom66,custom67,custom68,custom69,custom70,custom71,custom72,custom73,custom74,custom75,custom76,custom77,custom78,custom79,custom80,custom81,custom82,custom83,custom84,custom85,custom86,custom87,custom88,custom89,custom90,custom91,custom92,custom93,custom94,custom95,custom96,custom97,custom98,custom99,custom100,custom101,custom102,custom103,custom104,custom105,custom106,custom107,custom108,custom109,custom110,custom111,custom112,custom113', + // action: 'add_contact,add_file,add_photo_video,add_relationship,adjust_value,announcement,apex,approval,back,bug,call,canvas,change_owner,change_record_type,check,clone,close,defer,delete,description,dial_in,download,edit_groups,edit_relationship,edit,email,fallback,filter,flow,follow,following,freeze_user,goal,google_news,info,join_group,lead_convert,leave_group,log_a_call,log_event,manage_perm_sets,map,more,new_account,new_campaign,new_case,new_child_case,new_contact,new_event,new_group,new_lead,new_note,new_notebook,new_opportunity,new_person_account,new_task,new,password_unlock,preview,priority,question_post_action,quote,recall,record,refresh,reject,remove_relationship,remove,reset_password,scan_disabled,scan_enabled,script,share_file,share_link,share_poll,share_post,share_thanks,share,sort,submit_for_approval,update_status,update,upload,user_activation,user,view_relationship,web_link' } -export default class IndicatorBuilder extends LightningElement { - @api objectApiName = 'Account'; - @api fieldApiName = 'Name'; - @api fieldType; - @api showOneOrAll; - - // @wire(getObjectInfo, { objectApiName: "$objectApiName" }) - // wiredObjectInfo({ error, data }) { - // if (data) { - // console.log(`in wiredObjectInfo, found data`); - // let fieldData = data.fields[this.fieldApiName]; - // console.log(JSON.stringify(Object.keys(data.fields))); - // if (fieldData) { - // console.log(`found fieldData: ${JSON.stringify(fieldData)}`); - // } - // } - // } - - @track itemVariants = []; - - // indSize = 'large'; - // @api indShape = 'base'; - // @api indText = ''; - // @api indImage = ''; - // indIcon = 'standard:marketing_actions'; - // @api indHoverText; - // @api displayMode = 'showWhenValue'; - // indBackgroundColor; - // indForegroundColor; - - - showMatch = {}; - // iconSource = {}; - - @track fieldTypes = transformConstantObject(FIELD_TYPES); - @track showOneOrAllOptions = transformConstantObject(SHOW_ONE_OR_ALL); - - // showTextMatch = false; - // showNumberMatch = false; - // overrideColors = false; - - get objectAndFieldSelected() { - return this.objectApiName && this.fieldApiName; - } - -======= -import { LightningElement, api, track } from 'lwc'; +const FIELD_TYPES = { + TEXT: 'text', + NUMERIC: 'numeric', + DATE: 'date' +} export default class IndicatorBuilder extends LightningElement { + /* NOT IN USE */ + /* indSize = 'large'; @api indShape = 'base'; @api indText = ''; @@ -72,91 +31,55 @@ export default class IndicatorBuilder extends LightningElement { @api indHoverText = ''; indBackgroundColor; indForegroundColor; + */ + + @api indicator = {}; showMatch = {}; iconSource = {} showTextMatch = false; showNumberMatch = false; overrideColours = false; + + startTime; + endTime; + + showActiveVariant = false; + showSpinner = false; ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef get activeVariantTabIndex() { return this._activeVariantTabIndex; } set activeVariantTabIndex(value) { + this.showActiveVariant = false; this._activeVariantTabIndex = value; this.itemVariants = this.itemVariants.map((variant, index) => { variant.isActive = index == this.activeVariantTabIndex; return variant; }); + this.activeVariant = this.itemVariants[this.activeVariantTabIndex]; } _activeVariantTabIndex = 0; -<<<<<<< HEAD - get categorizedFieldType() { - let type = this.fieldTypes.options.find(fieldType => fieldType.dataTypes && fieldType.dataTypes.includes(this.fieldType)); - if (type) { - return type.value; - } else { - return this.fieldTypes.default.value; - } - // switch (this.fieldType) { - // case 'Integer': - // case 'Double': - // case 'Int': - // case 'Long': - // return 'number'; - // case 'DateTime': - // case 'Date': - // case 'Time': - // return 'date'; - // default: - // return '' - // } - } - - get filteredWhenToDisplayOptions() { - return this.whenToDisplayOptions.filter(option => !option.dataTypes || option.dataTypes.includes(this.categorizedFieldType)); - } - - get fieldTypeIsNumber() { - return this.categorizedFieldType === FIELD_TYPES.NUMBER.value; - } - - get itemVariantsString() { return JSON.stringify(this.itemVariants) }; - // { label: 'Default Indicator' } - // this.newIndicatorVariant('Default Indicator') - -======= + @track activeVariant = {}; @track itemVariants = []; + + @track iconOptions = []; // { label: 'Default Indicator' } // this.newIndicatorVariant('Default Indicator') ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef whenToDisplayOptions = [ { label: 'Is not blank', value: 'notBlank' }, { label: 'Is blank', value: 'isBlank' }, -<<<<<<< HEAD - { label: 'Contains text', value: 'containsText', dataTypes: [FIELD_TYPES.TEXT.value], showMatch: 'text' }, - { label: 'Equals text', value: 'equalsText', dataTypes: [FIELD_TYPES.TEXT.value], showMatch: 'text' }, - { label: 'Starts with text', value: 'startsWithText', dataTypes: [FIELD_TYPES.TEXT.value], showMatch: 'text' }, - { label: 'Equals number', value: 'equalsNumber', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'number' }, - { label: 'Is greater than', value: 'greaterThan', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'number' }, - { label: 'Is less than', value: 'lessThan', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'number' }, - { label: 'Is within range', value: 'inRange', dataTypes: [FIELD_TYPES.NUMBER.value], showMatch: 'numericRange' }, + { label: 'Contains text', value: 'containsText', fieldTypes: [FIELD_TYPES.TEXT], showMatch: 'text' }, + { label: 'Equals', value: 'equalsText', fieldTypes: [FIELD_TYPES.TEXT], showMatch: 'text' }, + { label: 'Equals', value: 'equalsNumber', fieldTypes: [FIELD_TYPES.NUMERIC], showMatch: 'number' }, + { label: 'Is greater than', value: 'greaterThan', fieldTypes: [FIELD_TYPES.NUMERIC], showMatch: 'number' }, + { label: 'Is less than', value: 'lessThan', fieldTypes: [FIELD_TYPES.NUMERIC], showMatch: 'number' }, + { label: 'Is within range', value: 'inRange', fieldTypes: [FIELD_TYPES.NUMERIC], showMatch: 'numericRange' }, // { label: 'Custom formula', value: 'customFormula' }, - // { label: 'Custom exception', value: 'customException' }, -======= - { label: 'Contains text', value: 'containsText', showMatch: 'text' }, - { label: 'Equals text', value: 'equalsText', showMatch: 'text' }, - { label: 'Equals number', value: 'equalsNumber', showMatch: 'number' }, - { label: 'Is greater than', value: 'greaterThan', showMatch: 'number' }, - { label: 'Is less than', value: 'lessThan', showMatch: 'number' }, - { label: 'Is within range', value: 'inRange', showMatch: 'numericRange' }, - { label: 'Custom formula', value: 'customFormula' }, - { label: 'Custom exception', value: 'customException' }, ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + // { label: 'Custom expression', value: 'customExpression' }, ]; iconSourceOptions = [ @@ -177,60 +100,6 @@ export default class IndicatorBuilder extends LightningElement { { label: 'Hide field label', value: 'hide' }, { label: 'Show standard label', value: 'standard' }, { label: 'Show custom label', value: 'custom' }, -<<<<<<< HEAD - ]; - - displayModeOptions = [ - { label: 'Display indicator when field is populated, hide indicator when field is blank', value: 'showWhenValue' }, - { label: 'Display indicator when field is blank, hide indicator when field is populated', value: 'showWhenBlank' }, - { label: 'Display indicator based on custom logic', value: 'customLogic' }, - ]; - - // get showColorOption() { - // return this.iconSource.sldsIcon || this.iconSource.staticText; - // } - - // get showColorSelectors() { - // return this.showColorOption && this.overrideColors; - // } - - get indicator() { - if (this.itemVariants?.length) { - return this.itemVariants[0]; - } - return {}; - } - - connectedCallback() { - console.log(`in indicatorBuilder connectedCallback`); - if (this.itemVariants.length === 0) { - console.log(`adding default variants`); - this.addNewVariant('has a value', 'notBlank'); - this.addNewVariant('is blank', 'isBlank'); - this.activeVariantTabIndex = 0; - } - this.setDefaultValues(); - } - - setDefaultValues() { - if (!this.showOneOrAll) { - this.showOneOrAll = this.showOneOrAllOptions.default.value; - } - } - - handleObjectFieldSelectorChange(event) { - console.log(`in handleObjectFieldSelectorChange, event.detail = ${JSON.stringify(event.detail)}`); - if (!event.detail) { - console.log(`Error: no event.detail in handleObjectFieldSelectorChange`); - return; - } - this.objectApiName = event.detail.objectValue; - this.fieldApiName = event.detail.fieldValue; - if (event.detail.fieldData?.length) { - this.fieldType = event.detail.fieldData[0].dataType; - } - -======= ] get showColourOption() { @@ -241,69 +110,33 @@ export default class IndicatorBuilder extends LightningElement { return this.showColourOption && this.overrideColours; } + /* LIFECYCLE HOOKS */ connectedCallback() { + this.processIconOptions(); if (this.itemVariants.length === 0) { console.log(`adding default variants`); this.addNewVariant('When field has value', 'notBlank'); this.addNewVariant('When field is blank', 'isBlank'); this.activeVariantTabIndex = 0; } ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef } - handleWhenToDisplayChange(event) { - let value = event.detail.value; - let matchingOption = this.whenToDisplayOptions.find(option => option.value == value); - if (matchingOption) { - this.showMatch = { [matchingOption.showMatch]: true }; + renderedCallback() { + if (this.endTime) { + console.log(`elapsed time on render = ${this.endTime - this.startTime}`); + this.endTime = null; + } + if (!this.showActiveVariant) { + this.showActiveVariant = true; } } - handleIconSourceChange(event) { - let value = event.detail.value; - let variantToUpdate = this.itemVariants[target.dataset.index]; - console.log(`value = ${value}`); - // this.iconSource = { [value]: true }; - variantToUpdate.iconSource = { [value]: true }; - } - - handleIconSelection(event) { - console.log(JSON.stringify(event.detail)); - this.indIcon = event.detail; - } - - handleStaticTextChange(event) { - this.indText = event.target.value; - } - -<<<<<<< HEAD - handleForegroundColorChange(event) { - this.indForegroundColor = event.target.value; - } - - handleBackgroundColorChange(event) { - this.indBackgroundColor = event.target.value; - } - - handleOverideColorsChange(event) { - this.overrideColors = event.target.checked; -======= - handleForegroundColourChange(event) { - this.indForegroundColor = event.target.value; - } - - handleBackgroundColourChange(event) { - this.indBackgroundColor = event.target.value; - } - - handleOverideColoursChange(event) { - this.overrideColours = event.target.checked; ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef - } - + /* EVENT HANDLERS */ handleAddVariantClick() { // this.itemVariants.push({ label: `Indicator Variant ${(this.itemVariants.length + 1)}`}); // this.itemVariants.push(this.newIndicatorVariant(`Indicator Variant ${(this.itemVariants.length + 1)}`)); + // this.startTime = Date.now(); + // console.log(`startTime: ${this.startTime}`); this.addNewVariant(`Indicator Variant ${(this.itemVariants.length + 1)}`); } @@ -313,25 +146,6 @@ export default class IndicatorBuilder extends LightningElement { console.log(`activeVariantTabIndex = ${this.activeVariantTabIndex}`); } -<<<<<<< HEAD - // handleDisplayModeChange(event) { - // this.displayMode = event.detail.value; - // this.showVariantLogic = this.displayMode == 'customLogic'; - // } - - handleIndicatorChange(event) { - console.log(`in handleIndicatorChange, detail = ${JSON.stringify(event.detail)}`); - if (event.detail) { - let variantToUpdate = this.itemVariants[event.detail.index]; - if (variantToUpdate && event.detail.propertyName) { - variantToUpdate[event.detail.propertyName] = event.detail.value; - this.itemVariants = [...this.itemVariants]; - } - } - } - -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef handleVariantPropertyChange(event) { if (event.currentTarget.dataset.property) { let target = event.currentTarget; @@ -349,7 +163,8 @@ export default class IndicatorBuilder extends LightningElement { console.log(`index is ${target.dataset.index}, value is ${value}, property name is ${target.dataset.property}`); - let variantToUpdate = this.itemVariants[target.dataset.index]; + // let variantToUpdate = this.itemVariants[target.dataset.index]; + let variantToUpdate = this.activeVariant; if (variantToUpdate) { variantToUpdate[target.dataset.property] = value; if (target.dataset.property === 'iconSource') { @@ -361,30 +176,38 @@ export default class IndicatorBuilder extends LightningElement { } } + handleVariantDeleteClick(event) { + event.preventDefault(); + event.stopPropagation(); + let index = event.target.dataset.index; + this.itemVariants.splice(index, 1); + if (this.itemVariants.length === 0) { + this.addNewVariant('Indicator Variant 1'); + } + } + + /* ACTION FUNCTIONS */ addNewVariant(label, whenToDisplay) { this.itemVariants.push(this.newIndicatorVariant(label, whenToDisplay)); this.activeVariantTabIndex = this.itemVariants.length - 1; + this.endTime = Date.now(); + console.log(`endTime: ${this.endTime}`); + console.log(`this took ${this.endTime - this.startTime}`); } newIndicatorVariant(label, whenToDisplay, isActive = true, iconSource = 'sldsIcon') { let whenToDisplayOptions = this.whenToDisplayOptions; -<<<<<<< HEAD - let index = this.itemVariants.length; -======= ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef let newVariant = { label, whenToDisplay, isActive, iconSource, -<<<<<<< HEAD - index, hoverText: '', - overrideColors: false, -======= - hoverText: '', ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + sourceValue: null, + // iconSourceIs: {}, + // filterTypeIs: {}, + get iconSourceIs() { return { [this.iconSource]: true } }, @@ -396,16 +219,6 @@ export default class IndicatorBuilder extends LightningElement { return 'slds-vertical-tabs__nav-item' + (this.isActive ? ' slds-is-active' : ''); }, get tabPaneClass() { -<<<<<<< HEAD - return 'slds-vertical-tabs__content slds-col ' + (this.isActive ? 'slds-show' : 'slds-hide'); - }, - get showColorOption() { - return this.iconSourceIs.sldsIcon; - }, - get showColorSelectors() { - return this.iconSourceIs.staticText || (this.showColorOption && this.overrideColors); - } -======= return 'slds-vertical-tabs__content ' + (this.isActive ? 'slds-show' : 'slds-hide'); }, get showColourOption() { @@ -414,9 +227,67 @@ export default class IndicatorBuilder extends LightningElement { get showColourSelectors() { return this.iconSourceIs.staticText || (this.showColourOption && this.overrideColours); } ->>>>>>> 73e5f784ff3ef05a4d7d8281abdb8191f0999bef + } console.log(`newVariant = ${JSON.stringify(newVariant)}`); return newVariant; } + + /* UTILITY FUNCTIONS */ + processIconOptions() { + let iconOptions = []; + for (let [iconCategory, iconString] of Object.entries(ICONS)) { + let iconNames = iconString.split(','); + iconNames.forEach(iconName => { + let val = `${iconCategory}:${iconName}`; + iconOptions.push({ + label: val, + value: val, + icon: val + }); + }) + } + console.log(`${iconOptions.length} total options`); + this.iconOptions = iconOptions; + // this.iconOptions.length = 50; + } + + /* + handleWhenToDisplayChange(event) { + let value = event.detail.value; + let matchingOption = this.whenToDisplayOptions.find(option => option.value == value); + if (matchingOption) { + this.showMatch = { [matchingOption.showMatch]: true }; + } + } + + handleIconSourceChange(event) { + let value = event.detail.value; + let variantToUpdate = this.itemVariants[target.dataset.index]; + console.log(`value = ${value}`); + // this.iconSource = { [value]: true }; + variantToUpdate.iconSource = { [value]: true }; + } + + handleIconSelection(event) { + console.log(JSON.stringify(event.detail)); + this.indIcon = event.detail; + } + + handleStaticTextChange(event) { + this.indText = event.target.value; + } + + handleForegroundColourChange(event) { + this.indForegroundColor = event.target.value; + } + + handleBackgroundColourChange(event) { + this.indBackgroundColor = event.target.value; + } + + handleOverideColoursChange(event) { + this.overrideColours = event.target.checked; + } + */ } \ No newline at end of file From cce243756eb23045a17a27d19fa995fcb8d8881a Mon Sep 17 00:00:00 2001 From: David Fromstein Date: Thu, 26 Sep 2024 14:20:12 -0700 Subject: [PATCH 17/23] Cleaning up code --- .../indicatorBuilder/indicatorBuilder.html | 269 ++++-------------- .../lwc/indicatorBuilder/indicatorBuilder.js | 77 ----- 2 files changed, 61 insertions(+), 285 deletions(-) diff --git a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html index 07bf79c..994200f 100644 --- a/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html +++ b/force-app/main/default/lwc/indicatorBuilder/indicatorBuilder.html @@ -14,7 +14,8 @@

- +
@@ -39,8 +40,8 @@

{variant.label} - + @@ -48,242 +49,94 @@

onclick={handleAddVariantClick}> - -

@@ -21,8 +21,8 @@ allow-multiselect={fieldAllowMultiselect} object-name={objectValue} available-field-types={availableFieldTypes} available-reference-types={availableReferenceTypes} default-to-name-field={defaultToNameField} disabled={fieldPicklistIsDisabled} - onchange={handleFieldChange} value={fieldValue} builder-context={builderContext} notify-on-clear - onclearrequest={handleFieldClearRequest}> + onchange={handleFieldChange} value={fieldValue} builder-context={builderContext} notify-on-clear={notifyOnClear} + onclearrequest={handleFieldClearRequest} include-full-details={includeFullDetails}>
diff --git a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js index 8d8cc69..de1a69b 100644 --- a/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js +++ b/force-app/main/default/lwc/fsc_objectFieldSelector/fsc_objectFieldSelector.js @@ -22,6 +22,7 @@ export default class Fsc_objectFieldSelector extends LightningElement { @api fieldAllowMultiselect = false; @api required = false; @api notifyOnClear = false; + @api includeFullDetails = false; @api availableObjectSelection = this.availableObjectOptions.default?.value; @api availableObjects; @@ -31,6 +32,10 @@ export default class Fsc_objectFieldSelector extends LightningElement { @api defaultToNameField; @api layout = LAYOUT_OPTIONS.VERTICAL.value; + @track selectedObjects = []; + @track selectedFields = []; + + @api get builderContext() { return this._builderContext; @@ -112,12 +117,6 @@ export default class Fsc_objectFieldSelector extends LightningElement { errorMessages.push(cmp.validate().errorMessage) } }) - // if (this.objectSelector && this.objectSelector.validate().errorMessage) { - // errorMessages.push(this.objectSelector.validate().errorMessage) - // } - // if (this.fieldSelector && this.fieldSelector.validate().errorMessage) { - // errorMessages.push(this.fieldSelector.validate().errorMessage) - // } console.log('in ofsValidate, errorMessages = ' + errorMessages); if (errorMessages.length) { return { @@ -167,21 +166,13 @@ export default class Fsc_objectFieldSelector extends LightningElement { handleObjectChange(event) { this.objectValue = event.detail.value; - // const attributeChangeEvent = new FlowAttributeChangeEvent( - // 'objectValue', - // this.objectValue - // ); - // this.dispatchEvent(attributeChangeEvent); + this.selectedObjects = event.detail.selectedObjects; this.dispatchValues(); } handleFieldChange(event) { this.fieldValue = event.detail.value; - // const attributeChangeEvent = new FlowAttributeChangeEvent( - // 'fieldValue', - // this.fieldValue - // ); - // this.dispatchEvent(attributeChangeEvent); + this.selectedFields = event.detail.selectedFields; this.dispatchValues(); } @@ -202,16 +193,12 @@ export default class Fsc_objectFieldSelector extends LightningElement { fieldValue: this.fieldValue, fieldValues: this.fieldValues } + if (this.includeFullDetails) { + detail.selectedObjects = this.selectedObjects; + detail.selectedFields = this.selectedFields; + } + console.log(`in objectFieldSelector dispatchValues: detail.selection lengths = ${detail.selectedObjects.length},${detail.selectedFields.length}`); + this.dispatchEvent(new CustomEvent('change', { detail })); } - - - connectedCallback() { - // console.log('displayType = ' + this.displayType); - // console.log('objectValue = ' + this.objectValue); - // console.log('availableFieldTypes = ' + this.availableFieldTypes); - // console.log('availableReferenceTypes = ' + this.availableReferenceTypes); - // console.log('hideObjectPicklist = ' + this.hideObjectPicklist); - // console.log('hideFieldPicklist = ' + this.hideFieldPicklist); - } } \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html index 735c69a..84cd801 100644 --- a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.html @@ -23,5 +23,6 @@ variant={variant} notify-on-clear={notifyOnClear} onclearrequest={handleClearRequest} + include-full-details={includeFullDetails} > \ No newline at end of file diff --git a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js index a0c061f..04eb92c 100644 --- a/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js +++ b/force-app/main/default/lwc/fsc_objectSelector/fsc_objectSelector.js @@ -26,6 +26,7 @@ export default class Fsc_objectSelector extends LightningElement { @api excludeSublabelInFilter = false; // If true, the 'sublabel' text of an option is not included when determining if an option is a match for a given search text. @api includeValueInFilter = false; // If true, the 'value' text of an option is included when determining if an option is a match for a given search text. @api notifyOnClear = false; + @api includeFullDetails = false; // @api availableObjectSelection = this.availableObjectOptions.default?.value; @api availableObjects = []; @@ -164,6 +165,9 @@ export default class Fsc_objectSelector extends LightningElement { value: this.value, values: this.values, } + if (this.includeFullDetails) { + detail.selectedObjects = this.objectOptions.filter(object => this.values.includes(object.value)); + } this.dispatchEvent(new CustomEvent('change', { detail })); } From e793a7a367ca5ee3d15e9358110fa189badcf296 Mon Sep 17 00:00:00 2001 From: tschug Date: Thu, 26 Sep 2024 19:46:35 -0400 Subject: [PATCH 20/23] SLDS Icon Static Resource CSV --- .../default/classes/SldsIconController.cls | 56 + .../classes/SldsIconController.cls-meta.xml | 5 + .../classes/SldsIconControllerTests.cls | 26 + .../SldsIconControllerTests.cls-meta.xml | 5 + .../lwc/indicatorBuilder/indicatorBuilder.js | 21 +- .../default/staticresources/SldsIcons.csv | 1453 +++++++++++++++++ .../SldsIcons.resource-meta.xml | 6 + 7 files changed, 1570 insertions(+), 2 deletions(-) create mode 100644 force-app/main/default/classes/SldsIconController.cls create mode 100644 force-app/main/default/classes/SldsIconController.cls-meta.xml create mode 100644 force-app/main/default/classes/SldsIconControllerTests.cls create mode 100644 force-app/main/default/classes/SldsIconControllerTests.cls-meta.xml create mode 100644 force-app/main/default/staticresources/SldsIcons.csv create mode 100644 force-app/main/default/staticresources/SldsIcons.resource-meta.xml diff --git a/force-app/main/default/classes/SldsIconController.cls b/force-app/main/default/classes/SldsIconController.cls new file mode 100644 index 0000000..a724921 --- /dev/null +++ b/force-app/main/default/classes/SldsIconController.cls @@ -0,0 +1,56 @@ +public with sharing class SldsIconController { + + static final String COMMA = ','; + static final String NEWLINE = '\r\n'; + static final String SPACE = ' '; + + public class Option { + @AuraEnabled + public String label {get; set;} + @AuraEnabled + public String value {get; set;} + @AuraEnabled + public String icon {get; set;} + } + + @AuraEnabled (cacheable=true) + public static List