Tag Archive for: Salesforce Flow

What’s new for Datatable and other UnofficialSF components

I’ve released a new version of the Datatable component (4.3.5).

In addition to the Remove Row Action, I’ve added a new Standard Row Action and improved reactivity with a new single “Actioned Row” output.  When a row is “actioned”, you can fire off other reactive screen components like Flow Launcher or Screen Actions.  This lets you now do almost anything you want when clicking on a row action.

The action can be configured as a clickable icon or a full button and can be put in the first or last column of the datatable.

Some flow elements such as Transform and Filter are still not directly referenceable in the resource picker so I’ve updated the picker and the Datatable CPE to allow manual entry of flow attributes for the record and pre-selected record collections.  For example: “{!MyFilter}”

Other Datatable changes include increasing the maximum column width from 1000px to 1500px.

I’ve addressed a few bugs as well.

  • Date field values that get adjusted by the timzoneoffset now are stored as YYYY-MM-DD.  Prior versions stored these as a datetime which caused issues with collection processors and action buttons.
  • The SelectedRowKeyValue output now gets cleared when no rows are selected.
  • When both pagination and single row selection are enabled, the prior selection will be cleared before setting the new selection.
  • Fixed search/filter errors when using special characters by escaping special characters in filter and search terms.
  • The correct url for record hyperlinks will be generated when running in a playground org.
  • Edited ApexDefined rows will be output as soon as changes are saved.  (Issue #1565)  
  • If multiple preselected rows are provided and single row selection is enabled, only the first record in the collection will be marked as preselected.

It’s been a busy winter for updates on Unofficialsf.com.

I released an Auto-Navigate component for flow screens and added some new reactive collection processors.  By adding reactive conditional visibility to the Auto-Navigate component you gain full control over navigating between flow screens without the user needing to click a Next or Previous button.  The UpsertRecordByKey action lets one upsert a record into a record collection by matching the value of a key field.  

For certain types of reactive screens, some components are designed to react to the outputs of other components on the same screen. However, the first time a screen loads, these components may not have a value available. The Reactive Record and Reactive Record Collection components are designed to “seed” a component with a starting value before it can react to a change in another component. Think of these like the flow formula function BLANKVALUE where you can assign an optional value to use if the primary value is null or blank.

Updates to the Flow Screen Components Base pack include an updated combobox which means that Action Button and Screen Action outputs can now be directly referenced by other custom components from unofficialsf.com.  CPE developers can take advantage of a new feature that lets users manually reference flow attributes that can’t be selected natively by the component.  QuickChoice was updated to support default values for dependent picklists on initial screen load.  A Master Label and a Required attribute were added to the Object and Field picker.  The Rich Text Input screen component is now reactive.

The Flow Actions Base Pack and the Collection Actions were updated to have all entries be at API 45.0 or later which avoids any issues enabling the ICU Locale Formats which is being enforced in Spring ‘25.

New or updated Flow Actions include GetCaseThreadToken, GetPicklistValues and Base64ToFileConverter

Be sure to Subscribe to updates by clicking on any Blog post on this page and entering your email address and clicking Subscribe.

Datatable with Row Actions calling a pop-up Screen Flow

Datatable with Row Actions calling a pop-up Screen Flow

Recently I wrote an article on how datatable row actions could be used to execute a Screen Action.  This is a great feature if you need to perform some unattended actions on a record in the datatable.

But what if you need to provide some additional input or interact with the data in the actioned record?  Action Buttons and Screen Actions can only run auto-launched flows, not screen flows.

I was able to work with Josh Dayment to enhance his new Flow Launcher action to launch a screen flow reactively instead of just from a button.  We also added the capability of passing records and record collections in and out of the launched flow.

There will be many different use cases for this new capability, but this article highlights how you could combine Datatable and Flow Launcher to edit fields that aren’t natively supported for inline editing such as Lookup and Multi-Select Picklist fields.

Here’s the flow in action.  Each time the row action button is clicked, a screen flow pops up allowing the user to edit some of the fields in the actioned record.  When they click Save Changes, the datatable gets refreshed with the changed record.


This is a simple flow where you get a collection of Account records and present them in a Datatable on a reactive screen.

The reactive screen displays a Datatable with row actions enabled.  4 additional reactive actions are added to handle the additional processing.  Each of these will be explained in more detail later.

  1. CP – Get First Record
    Extract the single record from the collection of actioned rows provided by the datatable.
  2. Flow Launcher – Sobject
    Launch a screen flow that will allow the user to edit fields in the record provided by the Get First Record action.
  3. CP – Upset Record By Key
    Upsert the updated record from the screen flow into the current record collection.
  4. CP – Reactive Record Collection
    Provide the active record collection to be displayed in the Datatable and used by the Upsert action.  If nothing has been processed yet, seed the flow with the original Get Records collection.  Otherwise, return the collection provided by the Upsert Record By Key action.

When you first build this flow, set the input collection for the Datatable to be the collection of Accounts from the Get Records.  You will come back later and update this once you add the other reactive actions to the screen.

Next, define the Row Action for the Datatable.  Currently, there is only a Remove Row action so select that and restrict the number of actioned rows to 1.


The Remove Row action in the Datatable outputs a collection of records actioned by the user.  In this case, the Datatable is configured to restrict the user to a single action at a time.  The Get First Record component extracts the first record from the collection of Removed (Actioned) Rows from the Datatable so you have the single record you need to pass to the screen flow.


The Flow Launcher will fire by reacting to any changes in the record output by the Get First Record action which fires any time a new record is provided by the Datatable row action.

To configure the Flow Launcher component to launch the flow reactively, set the “Hide Launch Button” attribute to True (1).  To have the flow pop-up in front of the Datatable, set the “Show Flow in Modal” attribute to True (2).  You can select the size of the modal with the “Modal Size” attribute (3).  Identify the flow to be launched by providing the active flow’s API name in the “Flow API Name” attribute (4).  Identify which resource in the launched flow to pass the record to with the name of the input variable in “Subflow Input Variable Name” (5) and the record you are passing to that variable in “Launched Flow Input Attribute – Record” (6).  You can force the user to complete the called flow instead of closing the modal manually, by setting the “Disable Close Icon” attribute to True (7).


The flow being launched takes the values in the input record and displays a screen with inputs for some of the record’s fields.


The field values from the input record are used as defaults for the inputs on the screen.


The Flow Launcher action is looking for an output attribute from the flow with a special name of OUTPUT_Record.  You should create that as an output attribute in your screen flow and assign the values from the screen inputs to the OUTPUT_Record fields.


NOTE: You still want the calling flow to refresh even if the user doesn’t make any changes.  You can force this by having a custom checkbox field on your record.  The called flow will always change this value by setting it using this formula (fToggleChange).


The Upsert Record By Key component takes the modified record from the screen flow and upserts it back into the record collection by replacing the matching record in the collection with the new record values from the screen flow.  The key field API name defaults to Id.  Like you did with Datatable, you first need to configure this by referencing the original Get Records collection.  This will be changed after you add the Reactive Record Collection component to the screen.


Finally, the Reactive Record Collection component acts like a reactive BLANKVALUE function for record collections.  If the Input Record Collection hasn’t been populated yet, it uses the Alternate Record Collection to “seed” the original output from the component.  In this flow, the collection is first seeded with the results of the Get Records flow element.  After that, the record collection is the output from the Upsert Record By Key component. This output is used to provide the reactive record collection to both the Datatable component and the Upsert Record By Key component.


Now that the Reactive Record Collection component has been added to the screen, go back to the Datatable and Upsert Record By Key and change the Get Records collection to the output collection from the Reactive Record Collection component.


NOTE: CP – Get First Record, CP – Upsert Record By Key and CP – Reactive Record Collection are new actions I created and are available in version 1.0.3 or later of Reactive Screen Components.  These also require version 3.2.4 or later of the Collection Processors.


I hope this example gives you some ideas for some other use cases for components like Datatables with Row Actions or Autolaunched Screen Flows or Reactive Collection Processors.  Add your ideas to the comments.

Check out the latest Datatable improvements!

Welcome to the next major release of Datatable.  There are a couple of amazing new features along with a few minor bug fixes.

There is now a new Remove Row Action available that allows the removal of individual rows from the Datatable. This can be useful in scenarios such as using the Datatable to display a list of items in a shopping cart and needing to provide users with the ability to remove items from the list.

In addition to setting a maximum number of records, you can specify the icon and color to be used for the action and put the action column on the left or the right of the Datatable.

New outputs are the collection of removed records, the collection of remaining records and the number of records removed.   This functionality works for both Salesforce objects and Apex Defined records.

Remove Row Action – Removed Rows & Remaining Rows are Reactive Outputs

You can even use this action to “select” records and specify a limit on the number of records that can be acted on.  This allows you to remove records from the Datatable once they have been selected.

Remove Row Action – Used for Selections with a Limit on the Number of Row Actions

As a time-saving bonus, even if you are not including a remove row action, the new Remaining Rows output collection will contain all the Datatable records including all Edits that were made to the records.  You no longer must add extra steps to your flow to combine the edited records with the original records. (How to use both the Selected and the Edited records in a Datatable)

Remaining Rows attribute can be used to output All Records with Edits

• There is a new option to display the number of Selected Records in the table header.  Even better, with this release, selected records are now PERSISTENT once selected.  Performing table actions such as Pagination, Sorting, Searching, Filtering and Removing Rows will always persist all previously selected records.

Selected Record Persistence with Pagination, Sort, Search, Filter, and Remove Row

• To help with debugging flows where you have multiple Datatables on the same screen, the Console Log outputs will identify the Datatable Header value for each console log statement.  To help protect sensitive information, record and field values will no longer show in the console log or debug log outputs.  You can still choose to override this behavior in your sandboxes with a couple simple attribute changes in the source code.

Override behavior showing record data
Default behavior with data hidden

Find the new package install links here.

Four New Collection Processor Actions added as Reactive Screen Components

I’ve added 4 new Collection Processor Actions as Reactive Screen Components. The original actions were Extract Field to Collection and Calculate Field Summary. The latest additions are Filter Collection, Find Common and Unique Records, Join Collections and Sort Collections.

This means you can now do multiple types of collection processing without having to leave the flow screen. And the amazing thing is that these components are all reactive to each other and any other flow screen components that support reactivity.

Read this article to see different use cases for these actions and to get the installation links to install them in your own org.

Reactive Screens: How to Turn a 7 Element Flow Into 1

When Winter ’23 release arrived, it brought with it Data Table and IN operator. I was excited to use them and wrote a blog on how it helped me solve a use case that was not possible to achieve with standard reports. I was happy with the 7 steps flow I created to achieve this
Now, a few releases later, Summer ‘23 is around the corner, and with it comes reactive screens and reactive formulas. I went back to my solution and was able to get the same result and reduce a 7 step flow to 1 screen. How awesome is that!!!

Reactive screens are currently in beta and you can try them out in a prerelease org running Summer ‘23 (don’t forget to opt in to the reactive screens beta under process automation settings in setup)

Here is how I did it

Reminder use case: display all open opportunities where the selected user is on the account team. Then display the account team role this user has for these accounts.

I used the new Data Fetcher component from Josh Dayment, and combined it with some complex SOQL queries that output the results into a Data Table.

To select the user, I added a lookup to the screen. This is currently the only reactive lookup element available. In order to get a list of users, you can point the component to any CreatedById lookup field from any object. I used the Account object.

My first formula (and make sure to use a formula resource, and not a variable or text template for this, as only formulas are reactive. Don’t ask me how I know 😉) queried the records for open opportunities

I fed this formula into the first data fetcher, and used a merge field to get the currently selected user from the screen.

The data fetcher queried records are displayed on screen using the Data Table component (Data Table is now GA, and also got some new enhancements in the summer release). The lookup component outputs the selected value and the selected label so I used another little formula to dynamically display the selected user name in the table title.

A similar process followed for the second table and showing the account team role

Look what I could achieve with just 4 formulas and one screen. Here is a demo of the finished flow and reactive functionality.

I can’t wait for this to be generally available to help us simplify multiple flows. For now this is only available in prerelease orgs and soon in sandboxes.

Data Fetcher on the AppExchange

Data Fetcher is a Lightning Web Component for Screen Flows that will query records based on a SOQL string, then provide an output of records (or single record) to be used on the same screen. What is so special about that you might ask? Well, let me tell you! With the reactive components beta for Screen Flows, you can now have components on a single screen react based on input from other components without ever leaving the screen. Data Fetcher was featured at TDX ’23 as part of a session on reactive screen components.

Let’s take an example using components from here on UnofficialSF. With Data Fetcher I can accept the selected choice value from Quick Choice* as my SOQL string and return records into a Data Table without having to click next. The records in the data table change depending on the choice I select – instantly. Before getting started ensure you have opted into the Reactive Screens Beta in Automation settings in your org instructions can be found here

Before reactive screens, this would have been accomplished using Lightning Messaging Service and Lightning Web Components, increasing the time to develop and go to market for this type of use case along with the costly maintenance of that LWC. With Data Fetcher an admin or developer can dynamically retrieve records on one screen without much additional lift, greatly enhancing the overall user experience and freeing up time for the admin or developer to work on other features for more important tasks.

In Summer ’23 formula resources will be reactive in flows – making this component significantly more powerful. With reactive formulas, Data Fetcher’s SOQL query string can now reference multiple components on the same screen which will create a truly dynamic experience. Pre-release orgs have already been enabled if you want to start testing now. Let’s look at a couple of examples.

The first example will use two Quick Choice components to help build my query utilizing a reactive formula. I will use the Quick Choice components to have the user select the Industry and Account Type of the Accounts I want to return on the Datatable those values will be used in a formula to return my SOQL string. (I am not doing it in this example but there is a really great video walkthrough on how you could use Quick Choice as a dependent picklist on the original post that could really enhance this use case)

//You can use this example to get started on your own formula//

"SELECT BillingCity, Id, Name, Phone, Industry, Type FROM Account WHERE Industry =" + {!choice.value} +" AND Type = " + {!Type.value}

In the below video, I am using the out-of-the-box lookup component to pass an Account Id to a SOQL string to populate all of the related contacts in a data table. A couple of years ago I presented on Automation Hour about using SOQL and SOSL in flow if you watch this video I had to build a SOQL query across multiple screens and decisions in order to perform the query inside of the flow. This Summer that will no longer be needed! Soon, an admin or developer will be able to add multiple components onto a single screen and use a formula variable to build a SOQL statement that then passes back the records on the screen as the user is interacting and/or changes different parts of the query and see the results as the changes are happening.

Note: Choices are not yet reactive as part of the beta. You will need to use Quick Choice if you want to bake choices (like a Picklist) into Data Fetcher queries.

For more information and to install Data Fetcher visit the AppExchange Listing here.

Learn more about the Reactive Screen Components Beta on Trailhead!

A Screen Component That Displays Fields in Read Only Mode

If you are building a form, you may want to make some screen components read only. In those cases, you can use this custom screen component that displays fields in read only mode.

How to Use the Component

1- Install the component using the installation links below.

2- Add a screen element and search for ReadOnlyScreenComponent. This is the name of the component that you installed.

3- This component can display 5 different data types: string (text), integer (number), checkbox, date, date/time. Enter the data type that you want to display. Valid values are string, integer, checkbox, date, and datetime.

Then provide the field label that the users will see.

Lastly, enter the value that you want it to display. Make sure that the value matches the data type that you entered.

4- Look and feel of the component changes according to the data type that you selected. Here is a read only screen that is built with ReadOnlyScreenComponent. Data types used in this flow are string, integer, date, datetime, and checkbox, respectively.

Read this post to see an example.


Installation Links

Use this link to install in production or developer edition environments.

Use this link to install in sandbox environments.


View Source

Here is the link to the source code repository.

Extending Flow Overview Video

Hi everyone! I recently worked on a video to help give an overview on when and why you might use Flow extensions. I also cover some good sample scenarios using various actions and also cover some lessons learned.

Check out the summary (with helpful clickable timestamps) below!

Here’s the video:

Slides (with the hyperlinks to the actions / other URLs) are here: https://docs.google.com/presentation/…

A Flow Screen Component that plays sounds

Created by Yumi Ibrahimzade

ABOUT
This is a Lightning Component that plays a sound effect.
It can be used on Flow Screens and Lightning Pages.
In order to play a sound, you have to upload the sound file as a Static Resource and then enter the name of the file to the “Sound File” parameter.

INSTALLATION

PARAMETERS
Sound File – Enter the name of the sound file.

CONSIDERATIONS
This component loads the sound file from Static Resources and plays it. So it is recommended to use smaller file sizes, otherwise it might take some time to load the file.

HOW TO USE
1- Upload the sound file as a Static Resource.

2- Add “SoundCMP” to your Flow Screen.
3- Enter the name of the sound file to the parameter called “Sound File”.

Use the Next Best Action REST API to execute a strategy and retrieve recommendation reactions

Quick guide on how to use the NBA REST API.  

Executing an NBA Strategy for a Given Record

Official documentation: https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_nba_recommendations.htm

Example:

POST

/services/data/v45.0/connect/recommendation-strategies/Jasmine_Yogurt_Service/recommendations

Body:

{
"contextRecordId" : "5001U000006XEpjQAG", 
"maxResults" : 4,
"strategyContext":{}
}

Response:

Raw Response (in JSON):

{
   "executionId":"23e8f474-6fec-4b5d-b2b5-667ef7ffb03a",
   "onBehalfOfId":"5001U000006XEpj",
   "recommendations":[
      {
         "acceptanceLabel":"Add Hot Waffle Press",
         "description":"Add a new Stanley Waffle Cone Press",
         "imageUrl":"https://isnba--c.documentforce.com/file-asset-public/WaffleMaker1?oid=00D1U0000012w03&v=1",
         "rejectionLabel":"No Thanks",
         "target":{
            "id":"0pr1U00000057IYQAY",
            "name":"Add a Hot Waffle Press",
            "type":"Recommendation",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IY"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "name":"Dispatch_Field_Technician",
            "parameters":[

            ],
            "type":"Flow"
         }
      },
      {
         "acceptanceLabel":"Upgrade to an X120 Soft Serve",
         "description":"Upgrade to a Twenty Gallon Single Nozzle Soft Serve Machine",
         "imageUrl":"https://isnba--c.documentforce.com/file-asset-public/SoftServeMaker1?oid=00D1U0000012w03&v=1",
         "rejectionLabel":"No Thanks",
         "target":{
            "id":"0pr1U00000057IXQAY",
            "name":"Upgrade to an X120 Soft Serve",
            "type":"Recommendation",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IX"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "name":"Dispatch_Field_Technician",
            "parameters":[

            ],
            "type":"Flow"
         }
      },
      {
         "acceptanceLabel":"Offer refinance",
         "description":"0% Refinancing on existing equipment",
         "imageUrl":"https://isnba--c.documentforce.com/file-asset-public/refinance?oid=00D1U0000012w03&v=1",
         "rejectionLabel":"No Thanks",
         "target":{
            "id":"0pr1U00000057IZQAY",
            "name":"0% Refinancing!",
            "type":"Recommendation",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IZ"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "name":"Dispatch_Field_Technician",
            "parameters":[

            ],
            "type":"Flow"
         }
      }
   ],
   "trace":{
      "messages":[

      ],
      "nodes":[

      ]
   }
}

Retrieving Recommendation Reactions

Official documentationhttps://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_nba_reactions.htm#connect_resources_nba_reactions

Example:

GET

/services/data/v45.0/connect/recommendation-strategies/reactions?targetId=0pr1U00000057IUQAY

This will return back all of the recommendations reactions for the recommendation with ID 0pr1U00000057IUQAY.

Similarly you can also query for the contextRecordId (e.g. Case with ID 5001U000006XEpjQAG, account, etc.)

GET

/services/data/v45.0/connect/recommendation-strategies/reactions/?contextRecordId=5001U000006XEpjQAG

RAW RESPONSE:

{
   "currentPageUrl":"/services/data/v45.0/connect/recommendation-strategies/reactions?page=0&pageSize=100",
   "nextPageUrl":"/services/data/v45.0/connect/recommendation-strategies/reactions?page=1&pageSize=100",
   "reactions":[
      {
         "contextRecord":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "createdBy":{
            "id":"0051U000004fPpPQAU",
            "url":"/services/data/v45.0/chatter/users/0051U000004fPpPQAU"
         },
         "createdDate":"2019-02-28T19:13:43.000Z",
         "id":"0ps1U000000TNzxQAG",
         "onBehalfOf":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "reactionType":"Accepted",
         "strategy":{
            "id":"0sg1U0000004edzQAA",
            "nameAtSnapshot":"Jasmine_Yogurt_Service"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "nameAtSnapshot":"Dispatch_Field_Technician"
         },
         "targetRecord":{
            "id":"0pr1U00000057IUQAY",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IUQAY"
         },
         "url":"/services/data/v45.0/connect/recommendation-strategies/reactions/0ps1U000000TNzxQAG"
      },
      {
         "contextRecord":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "createdBy":{
            "id":"0051U000004fPpPQAU",
            "url":"/services/data/v45.0/chatter/users/0051U000004fPpPQAU"
         },
         "createdDate":"2019-02-28T19:13:43.000Z",
         "id":"0ps1U000000TNzyQAG",
         "onBehalfOf":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "reactionType":"Accepted",
         "strategy":{
            "id":"0sg1U0000004edzQAA",
            "nameAtSnapshot":"Jasmine_Yogurt_Service"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "nameAtSnapshot":"Dispatch_Field_Technician"
         },
         "targetRecord":{
            "id":"0pr1U00000057IUQAY",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IUQAY"
         },
         "url":"/services/data/v45.0/connect/recommendation-strategies/reactions/0ps1U000000TNzyQAG"
      },
      {
         "contextRecord":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "createdBy":{
            "id":"0051U000004fPpPQAU",
            "url":"/services/data/v45.0/chatter/users/0051U000004fPpPQAU"
         },
         "createdDate":"2019-02-28T19:13:43.000Z",
         "id":"0ps1U000000TNzzQAG",
         "onBehalfOf":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "reactionType":"Accepted",
         "strategy":{
            "id":"0sg1U0000004edzQAA",
            "nameAtSnapshot":"Jasmine_Yogurt_Service"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "nameAtSnapshot":"Dispatch_Field_Technician"
         },
         "targetRecord":{
            "id":"0pr1U00000057IUQAY",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IUQAY"
         },
         "url":"/services/data/v45.0/connect/recommendation-strategies/reactions/0ps1U000000TNzzQAG"
      },
      {
         "contextRecord":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "createdBy":{
            "id":"0051U000004fPpPQAU",
            "url":"/services/data/v45.0/chatter/users/0051U000004fPpPQAU"
         },
         "createdDate":"2019-02-28T19:13:43.000Z",
         "id":"0ps1U000000TO00QAG",
         "onBehalfOf":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "reactionType":"Accepted",
         "strategy":{
            "id":"0sg1U0000004edzQAA",
            "nameAtSnapshot":"Jasmine_Yogurt_Service"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "nameAtSnapshot":"Dispatch_Field_Technician"
         },
         "targetRecord":{
            "id":"0pr1U00000057IUQAY",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IUQAY"
         },
         "url":"/services/data/v45.0/connect/recommendation-strategies/reactions/0ps1U000000TO00QAG"
      },
      {
         "contextRecord":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "createdBy":{
            "id":"0051U000004fPpPQAU",
            "url":"/services/data/v45.0/chatter/users/0051U000004fPpPQAU"
         },
         "createdDate":"2019-03-07T05:11:29.000Z",
         "id":"0ps1U000000TQzqQAG",
         "onBehalfOf":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "reactionType":"Accepted",
         "strategy":{
            "id":"0sg1U0000004edzQAA",
            "nameAtSnapshot":"Jasmine_Yogurt_Service"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "nameAtSnapshot":"Dispatch_Field_Technician"
         },
         "targetRecord":{
            "id":"0pr1U00000057IUQAY",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IUQAY"
         },
         "url":"/services/data/v45.0/connect/recommendation-strategies/reactions/0ps1U000000TQzqQAG"
      },
      {
         "contextRecord":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "createdBy":{
            "id":"0051U000004fPpPQAU",
            "url":"/services/data/v45.0/chatter/users/0051U000004fPpPQAU"
         },
         "createdDate":"2019-03-18T18:21:15.000Z",
         "id":"0ps1U000000TYoYQAW",
         "onBehalfOf":{
            "id":"5001U000006XEpjQAG",
            "url":"/services/data/v45.0/chatter/records/5001U000006XEpjQAG"
         },
         "reactionType":"Accepted",
         "strategy":{
            "id":"0sg1U0000004edzQAA",
            "nameAtSnapshot":"Jasmine_Yogurt_Service"
         },
         "targetAction":{
            "id":"3001U000000oZixQAE",
            "nameAtSnapshot":"Dispatch_Field_Technician"
         },
         "targetRecord":{
            "id":"0pr1U00000057IUQAY",
            "url":"/services/data/v45.0/connect/recommendations/0pr1U00000057IUQAY"
         },
         "url":"/services/data/v45.0/connect/recommendation-strategies/reactions/0ps1U000000TYoYQAW"
      }
   ]
}