Display Salesforce Lightning Web Component Data Table in Agentforce Output

Display Salesforce Lightning Web Component Data Table in Agentforce Output

Supercharge Agentforce with Salesforce LWC Data Tables: A Step-by-Step Guide

Unlock powerful data visualization within Agentforce Employee Agent by seamlessly integrating Salesforce Lightning Web Component (LWC) Data Tables. This comprehensive guide will walk you through building custom Salesforce Lightning types to display dynamic data, enhancing the user interface of your custom agent actions in Lightning Experience.

Are your Agentforce users craving a more intuitive and structured way to view data from custom actions? The default output might be functional, but imagine the impact of presenting information in a clear, sortable, and interactive data table directly within Agentforce. This is precisely what we’ll achieve by combining the power of Salesforce Apex, Lightning Web Components, and custom Lightning Types.

This blog post will delve into:

  • Why use LWC Data Tables in Agentforce?
  • Designing your Apex Invocable Method for Agentforce compatibility.
  • Building a reusable Lightning Web Component (LWC) for data display.
  • Configuring Custom Lightning Types for seamless integration.
  • Putting it all together: A practical example with Product Search.

Ready to elevate your Agentforce experience? Let’s dive in!

Why Use LWC Data Tables in Agentforce Output?

The Agentforce Employee Agent in Lightning Experience is designed to streamline agent workflows. While custom agent actions provide immense flexibility, presenting complex data in a raw format can hinder efficiency. Here’s why LWC Data Tables are a game-changer for Agentforce output:

  • Enhanced Readability: Data tables organize information into rows and columns, making it easy to scan and understand.
  • Improved User Experience: Agents can quickly grasp the relevant details without sifting through unstructured text.
  • Interactivity: LWC Data Tables offer built-in features like sorting and resizing columns, empowering agents to manipulate the data directly.
  • Consistency: Maintain a consistent look and feel with the rest of your Lightning Experience UI.
  • Scalability: Easily display varying amounts of data without compromising performance or layout.

By leveraging LWC Data Tables, you transform your Agentforce outputs from static text into dynamic, actionable insights, ultimately boosting agent productivity.

Step 1: Design Your Apex Invocable Method for Agentforce

The heart of our solution lies in an Apex InvocableMethod that fetches the data. For Agentforce to consume this data effectively, we need to define specific @InvocableVariable classes for both input and output. This ensures that Agentforce can correctly interpret the data structure.

Let’s look at our SearchProductController Apex class:

Sample Apex Code:

public with sharing class SearchProductController {

    @InvocableMethod(
        label='Search Products'
        description='Finds products based on the given criteria'
    )
    public static List < ProductResponse > searchProducts( List < ProductRequest > req ) {

        List < ProductWrapper > listProductWraps = new List < ProductWrapper > ();
        List < ProductResponse> productResponses = new List< ProductResponse >();

        ProductRequest request = req[ 0 ];
        Integer intCount = request.Count;
        String productName = request.Name;
        System.debug( 'Count: ' + intCount );
        System.debug( 'Product Name: ' + productName );

        List < Product2 > listProducts = [
            SELECT Id, Name, ProductCode
            FROM Product2
            WHERE Name LIKE :('%' + productName + '%')
            ORDER BY Name ASC
            LIMIT :intCount
        ];

        for ( Product2 objProduct : listProducts ) {

            System.debug('Product: ' + objProduct);
            ProductWrapper objWrap = new ProductWrapper(
                objProduct.Name,
                objProduct.ProductCode
            );
            System.debug( 'Product Object: ' + objWrap );
            listProductWraps.add( objWrap );

        }

        ProductResponse productResponse = new ProductResponse();
        productResponse.availableProducts = listProductWraps;
        System.debug( 'Product Responses: ' + productResponses );
        productResponses.add(productResponse);
        System.debug( 'Product Responses After Adding: ' + productResponses );

        return productResponses;
    }

    public class ProductRequest {

        @InvocableVariable
        public String Name;
        @InvocableVariable
        public Integer Count;

    }

    public class ProductResponse {

        @InvocableVariable
        public List < ProductWrapper > availableProducts;

    }

    public class ProductWrapper {

        @InvocableVariable
        public String productName;

        @InvocableVariable
        public String productCode;

        public ProductWrapper(
            String productName,
            String productCode
        ) {

            this.productName = productName;
            this.productCode = productCode;

        }

    }

}

Key takeaways from the Apex class:

  • @InvocableMethod: This annotation makes the searchProducts method callable from external services, including Agentforce actions.
  • ProductRequest: Defines the input parameters for our product search (e.g., Name, Count). Notice the @InvocableVariable annotation, which is crucial for Agentforce to pass values.
  • ProductResponse: This class encapsulates the output of our invocable method. It contains a list of ProductWrapper objects.
  • ProductWrapper: This inner class defines the structure of each product record returned. Each property (productName, productCode) is marked with @InvocableVariable, making it accessible to our Lightning Type.

Step 2: Build Your Lightning Web Component (LWC) Data Table

Next, we’ll create an LWC that receives the data from our Apex method and displays it in a lightning-datatable.

HTML (productSearchDetails.html):

HTML

<template>
    <lightning-card title="Products" icon-name="standard:product">
        <lightning-datatable
                data={products}
                columns={columns}
                hide-checkbox-column
                key-field="productCode">
        </lightning-datatable>
    </lightning-card>
</template>

JavaScript (productSearchDetails.js):

JavaScript

import { LightningElement, api } from 'lwc';

export default class ProductSearchDetails extends LightningElement {

    @api value; // This property will receive the data from Agentforce

    columns = [
        { label: 'Product Name', fieldName: 'productName' },
        { label: 'Product Code', fieldName: 'productCode' }
    ];

    get products() {

        let tempProducts = [];

        // Ensure 'value' exists and is an array before iterating
        if (this.value && Array.isArray(this.value)) {
            for ( const element of this.value ) {
                console.log( element );
                tempProducts.push( {
                    productName: element.productName,
                    productCode: element.productCode
                } );
            }
        }
        return tempProducts;
    }
}

LWC Explanation:

  • @api value;: This is the most critical part. The @api decorator makes the value property public and reactive. Agentforce will automatically pass the data structured according to our ProductWrapper Apex class into this value property.
  • columns: Defines the columns for our lightning-datatable, specifying the label (what’s displayed) and fieldName (which property from our ProductWrapper to map to).
  • get products(): This getter transforms the incoming value data into a format suitable for the lightning-datatable. It iterates through the value (which will be a list of ProductWrapper objects) and creates a new array of objects with productName and productCode properties. The added check if (this.value && Array.isArray(this.value)) ensures robustness if value is not yet populated or is not an array.
  • lightning-datatable: The core component for displaying tabular data.
    • data={products}: Binds the data from our products getter.
    • columns={columns}: Binds the column definitions.
    • hide-checkbox-column: Removes the default checkbox column.
    • key-field="productCode": Essential for performance and unique row identification in data tables.

XML Configuration (productSearchDetails.js-meta.xml):

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>64.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Product Details</masterLabel>
    <targets>
        <target>lightning__AgentforceOutput</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__AgentforceOutput">
        <sourceType name="lightning__listType" itemTypeName="c__productSearchResponse"/>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

js-meta.xml highlights:

  • <isExposed>true</isExposed>: Makes the LWC available for use in Lightning App Builder and other contexts.
  • <target>lightning__AgentforceOutput</target>: This is crucial! It explicitly makes our LWC available as an output type within Agentforce actions.
  • <targetConfig targets="lightning__AgentforceOutput">: This section is specifically for Agentforce output.
    • <sourceType name="lightning__listType" itemTypeName="c__productSearchResponse"/>: This tells Agentforce that our LWC expects a list of items, and each item’s structure is defined by the custom Lightning Type named c__productSearchResponse. This itemTypeName maps directly to the ProductResponse class in our Apex, specifically its availableProducts list which contains ProductWrapper objects.

Step 3: Configure Custom Lightning Types for Seamless Integration

Custom Lightning Types bridge the gap between your Apex output and your LWC input. They define how Agentforce should interpret the data returned by your Apex invocable method and which LWC should render it.

You’ll create a folder within your force-app/main/default/customMetadata directory (or similar, depending on your project structure) for your custom type. Let’s call it productSearchResponse.lightningType. Inside this folder, you’ll have two files: schema.json and renderer.json.

schema.json:

JSON

{
  "title": "Product Search",
  "description": "Product Search",
  "lightning:type": "@apexClassType/c__SearchProductController$ProductWrapper"
}

schema.json details:

  • "lightning:type": "@apexClassType/c__SearchProductController$ProductWrapper": This is the most important line. It explicitly tells Agentforce to map this custom type to the ProductWrapper inner class within our SearchProductController Apex class. This is because our LWC value property is expecting a list of ProductWrapper objects (which are nested within ProductResponse).

renderer.json:

JSON

{
    "collection": {
        "renderer": {
            "componentOverrides": {
                "$": {
                    "definition": "c/productSearchDetails"
                }
            }
        }
    }
}

renderer.json details:

  • "collection": Indicates that this renderer is for a collection (list) of items.
  • "componentOverrides": { "$": { "definition": "c/productSearchDetails" } }: This is where we tell Agentforce which LWC to use to render each item in the collection. The $ signifies that the entire collection should be rendered by our productSearchDetails LWC.

Putting It All Together: Agentforce Configuration

Once you’ve deployed these components to your Salesforce org, you can configure your Agentforce action:

  1. Create an Agent Action: Navigate to Setup -> Agentforce -> Agent Actions (or search for it).
  2. Define Inputs: When configuring your Agent Action, you’ll specify the inputs that map to your ProductRequest Apex class (e.g., “Product Name”, “Count”).
  3. Define Output: This is where the magic happens. For the output, select “Custom Salesforce Lightning Type”. You should then be able to choose your newly created Product Search type (which corresponds to c__productSearchResponse).

When an agent executes this action, the Apex controller will fetch the product data, and Agentforce will use your custom Lightning Type to render the ProductWrapper list beautifully within the lightning-datatable of your productSearchDetails LWC!

Conclusion

By following these steps, you can significantly enhance the user experience for your Agentforce Employee Agents. Displaying data in a well-structured and interactive lightning-datatable directly within Agentforce output not only improves readability but also empowers agents with immediate, actionable insights. This powerful combination of Apex, LWC, and custom Lightning Types unlocks a new level of customization and efficiency for your Salesforce Agentforce implementation.

Reference Article:

https://developer.salesforce.com/docs/einstein/genai/guide/lightning-types-example-collection-renderer.html

Ready to transform your Agentforce outputs? Start implementing these techniques today!

Leave a Reply