Skip to content

Commit 9bef19f

Browse files
docs: document custom step usage (#1125)
* docs: document custom step usage * Add ja-jp * Update docs/content/basic/custom-steps.md Co-authored-by: haleychaas <[email protected]> * Fix typo * Improve based on feedback * remove types from docs * Update based on feedback * Add the definitions in drop downs * Remove ack from exmple --------- Co-authored-by: haleychaas <[email protected]>
1 parent 08be044 commit 9bef19f

File tree

3 files changed

+307
-0
lines changed

3 files changed

+307
-0
lines changed

docs/content/basic/custom-steps.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
title: Listening and responding to custom steps
3+
lang: en
4+
slug: /concepts/custom-steps
5+
---
6+
7+
Your app can use the `function()` method to listen to incoming [custom step requests](https://api.slack.com/automation/functions/custom-bolt). Custom steps are used in Workflow Builder to build workflows. The method requires a step `callback_id` of type `str`. This `callback_id` must also be defined in your [Function](https://api.slack.com/concepts/manifests#functions) definition. Custom steps must be finalized using the `complete()` or `fail()` listener arguments to notify Slack that your app has processed the request.
8+
9+
* `complete()` requires **one** argument: `outputs` of type `dict`. It ends your custom step **successfully** and provides a dictionary containing the outputs of your custom step as per its definition.
10+
* `fail()` requires **one** argument: `error` of type `str`. It ends your custom step **unsuccessfully** and provides a message containing information regarding why your custom step failed.
11+
12+
You can reference your custom step's inputs using the `inputs` listener argument of type `dict`.
13+
14+
Refer to [the module document](https://slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html) to learn about the available listener arguments.
15+
16+
```python
17+
# This sample custom step formats an input and outputs it
18+
@app.function("sample_custom_step")
19+
def sample_step_callback(inputs: dict, fail: Fail, complete: Complete):
20+
try:
21+
message = inputs["message"]
22+
complete(
23+
outputs={
24+
"message": f":wave: You submitted the following message: \n\n>{message}"
25+
}
26+
)
27+
except Exception as e:
28+
fail(f"Failed to handle a custom step request (error: {e})")
29+
raise e
30+
```
31+
32+
<details>
33+
<summary>
34+
Example app manifest definition
35+
</summary>
36+
37+
```json
38+
...
39+
"functions": {
40+
"sample_custom_step": {
41+
"title": "Sample custom step",
42+
"description": "Run a sample custom step",
43+
"input_parameters": {
44+
"message": {
45+
"type": "string",
46+
"title": "Message",
47+
"description": "A message to be formatted by the custom step",
48+
"is_required": true,
49+
}
50+
},
51+
"output_parameters": {
52+
"message": {
53+
"type": "string",
54+
"title": "Messge",
55+
"description": "A formatted message",
56+
"is_required": true,
57+
}
58+
}
59+
}
60+
}
61+
```
62+
63+
</details>
64+
65+
---
66+
67+
### Listening to custom step interactivity events
68+
69+
Your app's custom steps may create interactivity points for users, for example: Post a message with a button.
70+
71+
If such interaction points originate from a custom step execution, the events sent to your app representing the end-user interaction with these points are considered to be _function-scoped interactivity events_. These interactivity events can be handled by your app using the same concepts we covered earlier, such as [Listening to actions](/concepts/action-listening).
72+
73+
_function-scoped interactivity events_ will contain data related to the custom step (`function_executed` event) they were spawned from, such as custom step `inputs` and access to `complete()` and `fail()` listener arguments.
74+
75+
Your app can skip calling `complete()` or `fail()` in the `function()` handler method if the custom step creates an interaction point that requires user interaction before the step can end. However, in the relevant interactivity handler method, your app must invoke `complete()` or `fail()` to notify Slack that the custom step has been processed.
76+
77+
You’ll notice in all interactivity handler examples, `ack()` is used. It is required to call the `ack()` function within an interactivity listener to acknowledge that the request was received from Slack. This is discussed in the [acknowledging requests section](/concepts/acknowledge).
78+
79+
```python
80+
# This sample custom step posts a message with a button
81+
@app.function("custom_step_button")
82+
def sample_step_callback(inputs, say, fail):
83+
try:
84+
say(
85+
channel=inputs["user_id"], # sending a DM to this user
86+
text="Click the button to signal the step completion",
87+
blocks=[
88+
{
89+
"type": "section",
90+
"text": {"type": "mrkdwn", "text": "Click the button to signal step completion"},
91+
"accessory": {
92+
"type": "button",
93+
"text": {"type": "plain_text", "text": "Complete step"},
94+
"action_id": "sample_click",
95+
},
96+
}
97+
],
98+
)
99+
except Exception as e:
100+
fail(f"Failed to handle a function request (error: {e})")
101+
102+
# Your listener will be called every time a block element with the action_id "sample_click" is triggered
103+
@app.action("sample_click")
104+
def handle_sample_click(ack, body, context, client, complete, fail):
105+
ack()
106+
try:
107+
# Since the button no longer works, we should remove it
108+
client.chat_update(
109+
channel=context.channel_id,
110+
ts=body["message"]["ts"],
111+
text="Congrats! You clicked the button",
112+
)
113+
114+
# Signal that the custom step completed successfully
115+
complete({"user_id": context.actor_user_id})
116+
except Exception as e:
117+
fail(f"Failed to handle a function request (error: {e})")
118+
```
119+
120+
<details>
121+
<summary>
122+
Example app manifest definition
123+
</summary>
124+
125+
```json
126+
...
127+
"functions": {
128+
"custom_step_button": {
129+
"title": "Custom step with a button",
130+
"description": "Custom step that waits for a button click",
131+
"input_parameters": {
132+
"user_id": {
133+
"type": "slack#/types/user_id",
134+
"title": "User",
135+
"description": "The recipient of a message with a button",
136+
"is_required": true,
137+
}
138+
},
139+
"output_parameters": {
140+
"user_id": {
141+
"type": "slack#/types/user_id",
142+
"title": "User",
143+
"description": "The user that completed the function",
144+
"is_required": true
145+
}
146+
}
147+
}
148+
}
149+
```
150+
151+
</details>
152+
153+
Learn more about responding to interactivity, see the [Slack API documentation](https://api.slack.com/automation/functions/custom-bolt#interactivity).
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
title: Listening and responding to custom steps
3+
lang: ja-jp
4+
slug: /concepts/custom-steps
5+
---
6+
7+
Your app can use the `function()` method to listen to incoming [custom step requests](https://api.slack.com/automation/functions/custom-bolt). Custom steps are used in Workflow Builder to build workflows. The method requires a step `callback_id` of type `str`. This `callback_id` must also be defined in your [Function](https://api.slack.com/concepts/manifests#functions) definition. Custom steps must be finalized using the `complete()` or `fail()` listener arguments to notify Slack that your app has processed the request.
8+
9+
* `complete()` requires **one** argument: `outputs` of type `dict`. It ends your custom step **successfully** and provides a dictionary containing the outputs of your custom step as per its definition.
10+
* `fail()` requires **one** argument: `error` of type `str`. It ends your custom step **unsuccessfully** and provides a message containing information regarding why your custom step failed.
11+
12+
You can reference your custom step's inputs using the `inputs` listener argument of type `dict`.
13+
14+
Refer to [the module document](https://slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html) to learn about the available listener arguments.
15+
16+
```python
17+
# This sample custom step formats an input and outputs it
18+
@app.function("sample_custom_step")
19+
def sample_step_callback(inputs: dict, fail: Fail, complete: Complete):
20+
try:
21+
message = inputs["message"]
22+
complete(
23+
outputs={
24+
"message": f":wave: You submitted the following message: \n\n>{message}"
25+
}
26+
)
27+
except Exception as e:
28+
fail(f"Failed to handle a custom step request (error: {e})")
29+
raise e
30+
```
31+
32+
<details>
33+
<summary>
34+
Example app manifest definition
35+
</summary>
36+
37+
```json
38+
...
39+
"functions": {
40+
"sample_custom_step": {
41+
"title": "Sample custom step",
42+
"description": "Run a sample custom step",
43+
"input_parameters": {
44+
"message": {
45+
"type": "string",
46+
"title": "Message",
47+
"description": "A message to be formatted by the custom step",
48+
"is_required": true,
49+
}
50+
},
51+
"output_parameters": {
52+
"message": {
53+
"type": "string",
54+
"title": "Messge",
55+
"description": "A formatted message",
56+
"is_required": true,
57+
}
58+
}
59+
}
60+
}
61+
```
62+
63+
</details>
64+
65+
---
66+
67+
### Listening to custom step interactivity events
68+
69+
Your app's custom steps may create interactivity points for users, for example: Post a message with a button.
70+
71+
If such interaction points originate from a custom step execution, the events sent to your app representing the end-user interaction with these points are considered to be _function-scoped interactivity events_. These interactivity events can be handled by your app using the same concepts we covered earlier, such as [Listening to actions](/concepts/action-listening).
72+
73+
_function-scoped interactivity events_ will contain data related to the custom step (`function_executed` event) they were spawned from, such as custom step `inputs` and access to `complete()` and `fail()` listener arguments.
74+
75+
Your app can skip calling `complete()` or `fail()` in the `function()` handler method if the custom step creates an interaction point that requires user interaction before the step can end. However, in the relevant interactivity handler method, your app must invoke `complete()` or `fail()` to notify Slack that the custom step has been processed.
76+
77+
You’ll notice in all interactivity handler examples, `ack()` is used. It is required to call the `ack()` function within an interactivity listener to acknowledge that the request was received from Slack. This is discussed in the [acknowledging requests section](/concepts/acknowledge).
78+
79+
```python
80+
# This sample custom step posts a message with a button
81+
@app.function("custom_step_button")
82+
def sample_step_callback(inputs, say, fail):
83+
try:
84+
say(
85+
channel=inputs["user_id"], # sending a DM to this user
86+
text="Click the button to signal the step completion",
87+
blocks=[
88+
{
89+
"type": "section",
90+
"text": {"type": "mrkdwn", "text": "Click the button to signal step completion"},
91+
"accessory": {
92+
"type": "button",
93+
"text": {"type": "plain_text", "text": "Complete step"},
94+
"action_id": "sample_click",
95+
},
96+
}
97+
],
98+
)
99+
except Exception as e:
100+
fail(f"Failed to handle a function request (error: {e})")
101+
102+
# Your listener will be called every time a block element with the action_id "sample_click" is triggered
103+
@app.action("sample_click")
104+
def handle_sample_click(ack, body, context, client, complete, fail):
105+
ack()
106+
try:
107+
# Since the button no longer works, we should remove it
108+
client.chat_update(
109+
channel=context.channel_id,
110+
ts=body["message"]["ts"],
111+
text="Congrats! You clicked the button",
112+
)
113+
114+
# Signal that the custom step completed successfully
115+
complete({"user_id": context.actor_user_id})
116+
except Exception as e:
117+
fail(f"Failed to handle a function request (error: {e})")
118+
```
119+
120+
<details>
121+
<summary>
122+
Example app manifest definition
123+
</summary>
124+
125+
```json
126+
...
127+
"functions": {
128+
"custom_step_button": {
129+
"title": "Custom step with a button",
130+
"description": "Custom step that waits for a button click",
131+
"input_parameters": {
132+
"user_id": {
133+
"type": "slack#/types/user_id",
134+
"title": "User",
135+
"description": "The recipient of a message with a button",
136+
"is_required": true,
137+
}
138+
},
139+
"output_parameters": {
140+
"user_id": {
141+
"type": "slack#/types/user_id",
142+
"title": "User",
143+
"description": "The user that completed the function",
144+
"is_required": true
145+
}
146+
}
147+
}
148+
}
149+
```
150+
151+
</details>
152+
153+
Learn more about responding to interactivity, see the [Slack API documentation](https://api.slack.com/automation/functions/custom-bolt#interactivity).

docs/sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const sidebars = {
4343
'basic/view_submissions',
4444
'basic/app-home',
4545
'basic/options',
46+
'basic/custom-steps',
4647
'basic/authenticating-oauth',
4748
'basic/socket-mode'
4849
],

0 commit comments

Comments
 (0)