Copyright ©
Mindbreeze GmbH, A-4020 Linz, 2024.
All rights reserved. All hardware and software names used are brand names and/or trademarks of their respective manufacturers.
These documents are strictly confidential. The submission and presentation of these documents does not confer any rights to our software, our services and service outcomes, or any other protected rights. The dissemination, publication, or reproduction hereof is prohibited.
For ease of readability, gender differentiation has been waived. Corresponding terms and definitions apply within the meaning and intent of the equal treatment principle for both sexes.
This document describes the integration of Mindbreeze InSpire Insight Applications with Salesforce.
A simple use case, is for example to embed an Insight App in a Salesforce page where a user can directly make use of the search results that are returned and provided by the Mindbreeze appliance. For detailed step-by-step instructions, you can either create a Lightning component as described in this section or create a Visualforce component as described in this section. After that you can use the Lightning App Builder to add your components as described in this section.
In addition, the integration of Mindbreeze in Salesforce can be extended by adding the following advanced use cases (as examples):
The descriptions and instructions contained in this document are based on Salesforce.
The Lightning Component framework can be used to embed a Mindbreeze Insight App in a Salesforce page.
In this section, you will create a simple lightning component that hosts your Mindbreeze Insight app within an iframe. Then, you will use the lightning app builder to drag and drop the new component into your Salesforce Home page.
For more complex interaction that requires communication between the Salesforce object and your Mindbreeze Insight App, please refer to the next section here where the alternative Visualforce page component must be used.
Please follow these steps to create a lightning component:
<aura:component implements="flexipage:availableForAllPageTypes" access="global">
<iframe src="https://mycompany.myInsightApp:<port#>"
width="100%"
height="800px"
frameBorder="none"
scrolling="auto" />
</aura:component>
Note: Adjust the height (in pixels) to fit in the place of the hosting salesforce page.
Visualforce is a framework that allows developers to build custom user interfaces that can be hosted natively on the Lightning platform. In one Visualforce (VF) page, you can directly add HTML tags, CSS and JavaScript via <script> tags.
In this section, you will create a VF page that hosts your Mindbreeze Insight app. Then, you will use the lightning app builder to drag and drop the new component into a Case record page.
Please follow these steps to create a Visualforce (VF) page:
Now, your Mindbreeze Insight App is embedded into the Case record page:
In this section, you will see how the Salesforce lightning app builder is used to insert components (e.g Custom Lightning component or Visualforce page) into your target Salesforce page.
Please apply the following steps:
This section describes how to send the value of the Subject field from the case record page to the VF search page to automatically search for the subject value when an agent initially visits a Case record page.
Please apply the following steps:
This section describes how to extend the existing integration by adding a new custom action button Attach To Case for each search result. Triggering this action button will attach the search result to the Case record page. In addition, you will create a new custom lightning component to fetch all the attached results of a visited Case and displays them in a table view.
In this step, you will create a custom object and add some fields to it. These fields will be displayed when a search result is attached to the case. A field can be considered as a one-to-one map of a search result property.
Example:
If you are interested to show the following search result properties (title, URL, source, and author), then you must create equivalent fields respectively and add them to your custom object.
Later on, we will show you how the mapping between the search result properties and the custom fields is done, then how the lightning component displays those fields in a table view in the case record page.
Please apply the following steps:
|
|
|
|
|
|
|
|
|
|
|
|
Custom controllers contain custom logic and data manipulation that can be used by a Visualforce page. For example, a custom controller can retrieve a list of items to be displayed and can create or delete records of a custom objects.
In this step, you will create the controller AttachResultController, which will do the following:
Please apply the following steps:
public class AttachResultController {
public AttachResultController(ApexPages.StandardController controller) {
}
public String ValueReturned {get; set;}
public void attachResultToCase() {
Id caseId = System.currentPageReference().getParameters().get('Id');
String resultName = ApexPages.currentPage().getParameters().get('resultName');
String resultUrl = ApexPages.currentPage().getParameters().get('resultUrl');
String source = ApexPages.currentPage().getParameters().get('source');
String author = ApexPages.currentPage().getParameters().get('author');
List<Attached_Result__c> existingAttachedResults = [
SELECT Name__c FROM Attached_Result__c
WHERE Case__r.Id = :caseId AND Name__c = :resultName
];
if (existingAttachedResults.size() > 0) {
this.ValueReturned = 'duplicate record';
} else {
Attached_Result__c newRec= new Attached_Result__c();
newRec.Name__c = resultName;
newRec.Result_Url__c = resultUrl;
newRec.Author__c = author;
newRec.Source__c = source;
newRec.Case__c = caseId;
insert newRec;
this.ValueReturned = 'reload component';
}
}
@AuraEnabled
public static List<Attached_Result__c> getAttachedResults(Id recordId) {
return [
SELECT Name__c, Result_Url__c, Source__c, Author__c
FROM Attached_Result__c
WHERE Case__r.Id = :recordId
];
}
@AuraEnabled
public static boolean removeAttachedResult(Id recordId, String name) {
delete [
SELECT Name__c FROM Attached_Result__c
WHERE Name__c =: name AND Case__r.Id = :recordId
];
return true;
}
}
Code Highlights:
In the function attachResultToCase, in the else block, you have created a new instance of your custom object created previously and then you mapped the search result properties to the fields of the custom object.
Please apply the following steps:
<aura:component implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" controller="AttachResultController">
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<aura:attribute name="recordId" type="Id" />
<aura:attribute name="AttachedResults" type="Attached_Result__c"/>
<aura:attribute name="AttachedResultsCount" type="String" />
<aura:attribute name="Columns" type="List" />
<lightning:card class="slds-card_boundary" iconName="standard:case" title="{! 'Case Attached Results (' + v.AttachedResultsCount + ')' }">
<!-- Attached Results list goes here -->
<lightning:datatable data="{! v.AttachedResults }"
class="tableHeader"
columns="{! v.Columns }"
keyField="Id"
hideCheckboxColumn="true"
onrowaction="{! c.handleRowAction }"
wrapTextMaxLines="1" />
</lightning:card>
</aura:component>
({
doInit : function(component, event, helper) {
window.addEventListener("message", $A.getCallback(function(event) {
if (event.data === 'reloadComponent') {
helper.renderResults(component);
}
}), false);
var rowActions = [{
'label': 'Delete',
'iconName': 'utility:delete',
'name': 'delete'
}];
component.set("v.Columns", [
{label:"Result Name", fieldName:"Name__c", type:"text", wrapText: true},
{label:"Result Url", fieldName:"Result_Url__c", type:"url", wrapText: true},
{label:"Source", fieldName:"Source__c", type:"text", wrapText: true},
{label:"Author", fieldName:"Author__c", type:"text", wrapText: true},
{type: 'action', typeAttributes: { rowActions: rowActions }}
]);
helper.renderResults(component);
},
handleRowAction: function (cmp, event, helper) {
var action = event.getParam('action');
var row = event.getParam('row');
switch (action.name) {
case 'delete':
helper.removeResult(cmp, row);
break;
}
}
})
({
renderResults: function(component) {
var action = component.get("c.getAttachedResults");
if (action) {
action.setParams({
recordId: component.get("v.recordId")
});
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var data = response.getReturnValue();
component.set("v.AttachedResultsCount", data.length);
component.set("v.AttachedResults", data);
}
});
$A.enqueueAction(action);
}
},
removeResult: function (cmp, row) {
var action = cmp.get("c.removeAttachedResult");
if (action) {
action.setParams({
recordId: cmp.get("v.recordId"),
name: row.Name__c
});
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var rows = cmp.get('v.AttachedResults');
var rowIndex = rows.indexOf(row);
rows.splice(rowIndex, 1);
cmp.set('v.AttachedResults', rows);
cmp.set('v.AttachedResultsCount', rows.length);
}
});
$A.enqueueAction(action);
}
}
})
.THIS .tableHeader thead th button {
visibility: hidden;
display: none;
}
.THIS {
margin-bottom: 10px;
}
.THIS div.slds-card__header {
border-bottom: var(--lwc-borderWidthThin) solid var(--lwc-cardColorBorder);
padding: 8px !important;
background: var(--lwc-pageHeaderColorBackground,rgb(243, 242, 242));
}
.THIS div.slds-card__body {
margin-top: -8px;
}
In this step, the action button Attach To Case will be added to each search results. In addition, you will add the handler function which is fire when the action button is triggered.
Please apply the following steps:
Click Save and return back to any Case page.
In the search results, you will see the new custom action button:
Click on the Attach To Case button and the search result will be displayed in a table view:
Example: Result URL field has a maximum length of 255 characters
If a link is longer than 255 characters, an error occurs.
Workaround: Display instead a string “Result Url is too long”
How?
In your VF page, at the Mindbreeze require <script> tag, at the attachResult function, add the following yellow highlighted code:
<script>
Mindbreeze.require(["client/application", "api/v2/api", "underscore"], function(Application, API, _) {
var subject = "{! Case.Subject }";
var App = Application.extend({
prepareModels: function() {
this.setUnparsedUserQuery(subject);
},
attachResult: function(options) {
var model = options.model;
var actions = model.get("actions");
var filename = model.get()["title"].data[0].value;
var source = model.get('category') + '/' + model.get('categoryinstance');
var author = model.get('Author') || 'N/A';
var openAction = _.find(actions, function(action) {
return action.id == "Open";
});
if(!openAction) {
openAction = _.find(actions, function(action) {
return action.href;
});
}
if(openAction && openAction.href.length > 255) {
openAction.href = 'Result URL is too long';
}
/* Passing result to controller */
AttachToCase(filename, openAction.href, source, author);
}
});
var application = new App();
});
</script>
Example below requests the Author and extension properties:
First, in your Insight App snippet, add the following html:
<span style="display:none">{{Author}}{{extension}}</span>
And then in the attach result function at the <script> tag:
var author = model.get('Author') || 'N/A';
var extension = model.get('extension');
In the browser console (F12), you see the following error:
Uncaught SyntaxError: Unexpected token & in JSON at position 2
In the VF page, in your html code snippet of your search app replace the following code:
data-action-object="{"resetSearch":{}}"