Building a Slack App: Designing a UI This post is a continuation of our series based on that integrate with Salesforce APIs. With the from Salesforce, Slack app developers can offload common concerns like Salesforce authentication, directory hierarchies, reusable code, and deployments to Heroku. The end result is less time spent wrangling code and more time building features for your app. a video series explaining how to build Slack Apps Slack Starter Kit , we familiarized ourselves with the starter kit and set up our development environment to build a basic Slack app. In this post, we’ll continue building on that Slack app, focusing on how the Slack Starter Kit makes it easy to develop two essential components of every Slack app: In our last post Listening for user interactions Drawing a user interface. Responding to events If you’ve ever developed a front-end web app using JavaScript or CSS, you’re probably familiar with the basic tenets of event handling. Events in this context are defined as the actions a user takes on your website. For example, a mouse pointer clicking on a link emits an event; a pointer linking over a piece of text emits ; a keyboard keystroke emits ; and so on. onclick onhover onkeypressed In Slack, there’s a you can listen to, ranging from individual events (when a message is posted or pinned) to global changes (when channel names or visibilities are changed) to the administrative (when an app is installed or a new emoji is uploaded). is truly impressive. The process for listening to an event is as follows: multitude of events The full list of emitted events First, your app needs to define a webhook URL. This is a path on your server which can receive POST requests from Slack. Next, in your App Manifest, you identify the events which you’d like to capture. When an event occurs in a workspace where your app is installed, a JSON payload is sent to your app. Every event has its own unique payload. When your app receives the event from Slack, you can do anything you want: respond to the user, pop open a dialog to ask for more information, or simply store some information away in your database. There’s only one important point to remember: . This is to let Slack know that your app received its payload and is working on a response. You can do that work in the background—perhaps on a different thread, taking as long as you need—but only after you let Slack know everything is . you must respond to Slack within three seconds 200 OK Let’s take a look at how event handling works in practice. Head on over to your App Manifest, and scroll down to the bottom of the page, near the key. It should look like this: settings settings: event_subscriptions: request_url: https://<your-app-name>.herokuapp.com/slack/events bot_events: - app_home_opened interactivity: is_enabled: true request_url: https://<your-app-name>.herokuapp.com/slack/events This section identifies where Slack should send its payload once an event occurs. The key already defines one event to listen to, , which is triggered once your app is opened in Slack. bot_events app_home_opened Now, open up the local copy of your Starter Kit in your IDE; navigate to . As we saw in the last post, the Starter Kit has an opinionated directory structure to resolve any ambiguities as to where modifications should be made. In this case, the events folder is responsible for defining all of our event responses, just like the shortcuts folder defined our slack command in the previous article. Search for the first occurrence of the following line: apps/slack-salesforce-starter-app/listeners/events/app-home-opened.js client.views.publish As the method name implies, this function uses a Slack SDK to call . The main view for this event is created by a function called , which can be found in . an API named views.publish authorization_success_screen apps/slack-salesforce-starter-app/user-interface/app-home/auth-success.js Let’s make a few changes to these files. On line 16, add this line to fetch the timestamp of the event: let event_ts = event.event_ts; Change both calls to include this variable as a new argument: authorization_success_screen view: authorization_success_screen( currentuser.username, event_ts ) Finally, open up , change the method signature to include event_ts, and modify the displayed string to include this information: auth-success.js 'use strict'; const { HomeTab, Blocks } = require('slack-block-builder'); const authorization_success_screen = (username, event_ts) => { // preceding code remains unchanged Blocks.Section({ text: `It's ${event_ts}, and you are successfully authenticated to Salesforce as ${username}.` }) ); // continued code remains unchanged Commit this change, and deploy it to Heroku as before: $ git add . $ git commit -m "Add event timestamp" $ git push heroku main When the deployment is done, navigate to your app’s tab in the left-hand Slack menu. You should see a different string, which shows the timestamp of when you opened the app. Creating a UI Responding to can be a useful event to listen to whenever your app needs a centralized location to fetch data. Because of this, our next step will be to fetch data from Salesforce and present it in our Slack UI. app_home_opened To design and present layouts, Slack provides a system known as . Just as HTML is a markup language for the web, and Visualforce is a markup language for Salesforce, Block Kit is a markup language for Slack—except it uses JSON. For example, here’s what a button designed in Block Kit might look like: Block Kit { "type": "button", "text": { "type": "plain_text", "text": "Save" }, "style": "primary" } Block Kit ensures that every Slack App has a consistent user interface. Because of this, there’s a limited set of UI elements that you can use. When working with Block Kit, you design your layout in JSON. Then, you use the Slack API to POST that JSON to a channel, tab, or direct message. We already have a system in place for listening to an event and presenting text, so let’s build on that foundation. Before we work in Slack, though, let’s add some data to our fresh Salesforce org. To launch your browser directly to your Salesforce org, you can run the following command: sfdx force:org:open In the Setup menu, search for the . Choose CSV as your data type, then copy-paste the following lines into a new file called data.csv: Data Import Wizard Contact First Name, Contact Last Name, Contact Description Arden, Isabela, Lorem ipsum dolor sit amet Rowina, Arti, Proin a est sit amet quam varius efficitur. Aislin, Oedipus, Praesent et euismod sem Sindri, Filbert, Proin facilisis sit amet libero vulputate sodales Cyril, Gratien, Nulla at massa eu turpis venenatis egestas Upload this file as your data source. Importing this data should only take a minute or two. You can navigate to the Contacts tab if you’d like to be extra sure and verify that these names exist. Next, we’re going to make changes similar to the ones we made before when adding the event timestamp. A variable called is available to use, which serves as a connection to Salesforce. We can use it to query for Contact data, which is what we’re interested in displaying in Slack. conn Navigate to . We’ll the resolving of the promise in this function, and we’ll include the existing variable as a new argument: apps/slack-salesforce-starter-app/user-interface/app-home/auth-success.js await conn view: await authorization_success_screen( currentuser.username, event_ts, conn ) And once again, open up and change the method signature to include . You also need to declare the function as : auth-success.js conn async 'use strict'; const { HomeTab, Blocks } = require('slack-block-builder'); const authorization_success_screen = async (username, event_ts, conn) => { // continued code remains unchanged for now Next, with this connection, we’re going to issue a query to Salesforce to get our newly created Contact records. We’ll then display them in the Home tab of our Slack app. Since we already have a connection to Salesforce, fetching the data is as easy as issuing an SQL query. Place this code right before the place where the variable is defined: homeTab const result = await conn.query( `SELECT Name, Description FROM Contact` ); let records = result.records; let fields = records.map((record) => { return `*${record.Name}*: ${record.Description}`; }); Then, at the bottom of the blocks method call, add these lines, which represent the UI you’re constructing out of Block Kit: Blocks.Section({ text: `It's ${event_ts}, and you are successfully authenticated to Salesforce as ${username}.` }), Blocks.Header({ text: 'Contacts' }), Blocks.Divider(), Blocks.Section({ text: fields.join('\n') }) If you navigate back to your Slack App’s Home tab, you’ll see your organization’s list of contacts! Learning more We’ve built a Slack app that fetches data from Salesforce and presents that data in a UI using a framework called Block Kit. In our next post, we’ll send data from Slack to Salesforce! back Before then, you might want to familiarize yourself with how Block Kit works. Slack provides the , which is a playground for their UI elements. Under the hood, the Slack Starter Kit uses the to simplify the UI assemblage we worked with. Block Kit Builder Block Builder